Files
IIabm/AmendFirm_20230216.ipynb
T
2023-05-15 10:42:16 +08:00

1.3 MiB

In [1]:
import pandas as pd
import numpy as np
import math
import statsmodels.formula.api as smf
from sklearn.preprocessing import MinMaxScaler
import networkx as nx
import matplotlib.pyplot as plt
import seaborn as sns

plt.rcParams['font.sans-serif'] = 'SimHei'

# init graph bom
BomNodes = pd.read_csv('BomNodes.csv', index_col=0)
BomNodes.set_index('Code', inplace=True)
BomCateNet = pd.read_csv('BomCateNet.csv', index_col=0)
BomCateNet.fillna(0, inplace=True)

G = nx.from_pandas_adjacency(BomCateNet, create_using=nx.MultiDiGraph())

labels_dict = {}
for code in G.nodes:
    labels_dict[code] = BomNodes.loc[code].to_dict()
nx.set_node_attributes(G, labels_dict)

# load firm
Firm = pd.read_csv("Firm.csv")
Firm_copy = Firm.copy()

# add attribute, number of firm, to graph bom
firm_num_dict = {}
for node in nx.nodes(G):
    firm_num_dict[node]= sum(Firm_copy[node]==1)
nx.set_node_attributes(G, firm_num_dict, name="Num_Firm")

# get log revenue
Firm_copy['Revenue_Log'] = Firm_copy['Revenue'].map(math.log)
Firm_copy['Num_Employ_Log'] = Firm_copy['Num_Employ'].map(math.log)
data_ols = Firm_copy[Firm_copy[['Revenue_Log', 'Num_Employ_Log']].notnull().all(axis=1)][['Revenue_Log', 'Num_Employ_Log']]

ols_model = smf.ols('Revenue_Log ~ Num_Employ_Log', data=data_ols)
ols_results = ols_model.fit()
b = ols_results.params.Intercept
a = ols_results.params.Num_Employ_Log
print(ols_results.summary())
sns.regplot(x='Num_Employ_Log',y='Revenue_Log',data=data_ols[data_ols.notnull().all(axis=1)])

Firm_copy.loc[Firm_copy['Revenue_Log'].isnull(), 'Revenue_Log'] = Firm_copy[Firm_copy['Revenue_Log'].isnull()]['Num_Employ_Log'].map(lambda x: a*x + b)
series_Revenue_Log = Firm_copy.pop('Revenue_Log')
Firm_copy.insert(Firm_copy.columns.get_loc('Revenue'),'Revenue_Log', series_Revenue_Log)
series_Num_Employ_Log = Firm_copy.pop('Num_Employ_Log')
Firm_copy.insert(Firm_copy.columns.get_loc('Num_Employ'),'Num_Employ_Log', series_Num_Employ_Log)

# lift firm from neighboring tier
node_list = list(nx.bfs_tree(G, '1'))
node_list.reverse()

# init criterion for ending the lifting process
node_check = [k for k, v in nx.get_node_attributes(G, 'Num_Firm').items() if v==0]
if '1' in node_check:
    node_check.remove('1')
for node in node_check:
    if G.out_degree(node) == 0:
        node_check.remove(node)
        print(f"Warning: node, {node}, in tier 0 does not contain firm")

while node_check:
    for node in node_list[:-1]:
        if G.out_degree(node) > 0 and sum(Firm_copy[node]==1) == 0:
            list_neighbors = list(G.neighbors(node))
            firm_list = Firm_copy.index[(Firm_copy[list_neighbors]==1).all(axis=1)].to_list()
            if firm_list: # there exist firm that produces all components
                # lift firm with size above average in firm_list
                average_size = Firm_copy.loc[firm_list, 'Revenue_Log'].mean()
                firm_selected_list = Firm_copy.loc[firm_list].loc[Firm_copy.loc[firm_list, 'Revenue_Log'] >= average_size].index.to_list()
                Firm_copy.loc[firm_selected_list, node] = 1
                Firm_copy.loc[firm_selected_list, list_neighbors] = np.nan
            else: # select top 15% firm in terms of size
                firm_list = Firm_copy.index[(Firm_copy[list_neighbors]==1).any(axis=1)].to_list()
                firm_df = Firm_copy.loc[firm_list].sort_values('Revenue_Log', ascending=False)
                num_firm_selected = round(firm_df.shape[0] * 0.15)
                firm_selected_list = firm_df.index[0: num_firm_selected].to_list()
                Firm_copy.loc[firm_selected_list, node] = 1
                Firm_copy.loc[firm_selected_list, list_neighbors] = np.nan

    # update attribute, number of firm
    for node in nx.nodes(G):
        firm_num_dict[node]= sum(Firm_copy[node]==1)
    nx.set_node_attributes(G, firm_num_dict, name="Num_Firm")

    # update criterion for ending the lifting process
    node_check = [k for k, v in nx.get_node_attributes(G, 'Num_Firm').items() if v==0]
    if '1' in node_check:
        node_check.remove('1')
    for node in node_check:
        if G.out_degree(node) == 0:
            node_check.remove(node)
            print(f"Warning: node, {node}, in tier 0 does not contain firm")

# output
# Firm_copy.to_csv('Firm_amended.csv', index=False, encoding='utf-8-sig')
                            OLS Regression Results                            
==============================================================================
Dep. Variable:            Revenue_Log   R-squared:                       0.586
Model:                            OLS   Adj. R-squared:                  0.580
Method:                 Least Squares   F-statistic:                     94.86
Date:                Sat, 01 Apr 2023   Prob (F-statistic):           1.85e-14
Time:                        18:07:54   Log-Likelihood:                -128.58
No. Observations:                  69   AIC:                             261.2
Df Residuals:                      67   BIC:                             265.6
Df Model:                           1                                         
Covariance Type:            nonrobust                                         
==================================================================================
                     coef    std err          t      P>|t|      [0.025      0.975]
----------------------------------------------------------------------------------
Intercept         14.3160      0.806     17.757      0.000      12.707      15.925
Num_Employ_Log     0.9728      0.100      9.740      0.000       0.773       1.172
==============================================================================
Omnibus:                       55.594   Durbin-Watson:                   1.958
Prob(Omnibus):                  0.000   Jarque-Bera (JB):              244.671
Skew:                           2.451   Prob(JB):                     7.42e-54
Kurtosis:                      10.815   Cond. No.                         34.6
==============================================================================

Notes:
[1] Standard Errors assume that the covariance matrix of the errors is correctly specified.
['1', '1.1', '1.2', '1.3', '1.4', '2', '1.1.1', '1.1.2', '1.1.3', '1.2.1', '1.2.2', '1.2.3', '1.3.1', '1.3.2', '1.3.3', '1.3.4', '1.3.5', '1.4.1', '1.4.2', '1.4.3', '1.4.4', '1.4.5', '2.1', '2.2', '2.3', '1.3.1.1', '1.3.1.2', '1.3.1.3', '1.3.1.4', '1.3.1.5', '1.3.1.6', '1.3.1.7', '1.3.2.1', '1.3.3.1', '1.3.3.2', '1.3.3.3', '1.3.3.4', '1.3.3.5', '1.3.3.6', '1.3.3.7', '1.3.4.1', '1.3.4.2', '1.3.4.3', '1.3.5.1', '1.4.1.1', '1.4.1.2', '1.4.1.3', '1.4.1.4', '1.4.1.5', '1.4.2.1', '1.4.2.2', '1.4.2.3', '1.4.2.4', '1.4.2.5', '1.4.2.6', '1.4.2.7', '1.4.3.1', '1.4.3.2', '1.4.3.3', '1.4.3.4', '1.4.3.5', '1.4.3.6', '1.4.4.1', '1.4.4.2', '1.4.4.3', '1.4.4.4', '1.4.4.5', '1.4.5.1', '1.4.5.2', '1.4.5.3', '1.4.5.4', '1.4.5.5', '1.4.5.6', '1.4.5.7', '1.4.5.8', '1.4.5.9', '2.1.1', '2.1.2', '2.1.3', '2.1.4', '2.3.1', '2.3.2', '2.3.3', '2.1.1.1', '2.1.1.2', '2.1.1.3', '2.1.1.4', '2.1.1.5', '2.1.2.1', '2.1.2.2', '2.1.2.3', '2.1.2.4', '2.1.3.1', '2.1.3.2', '2.1.3.3', '2.1.3.4', '2.1.3.5', '2.1.3.6', '2.1.3.7', '2.1.4.1', '2.1.4.2', '2.1.4.1.1', '2.1.4.1.2', '2.1.4.1.3', '2.1.4.1.4', '2.1.4.2.1', '2.1.4.2.2']
C:\Users\ASUS\AppData\Local\Temp\ipykernel_17316\1464358194.py:49: PerformanceWarning: DataFrame is highly fragmented.  This is usually the result of calling `frame.insert` many times, which has poor performance.  Consider joining all columns at once using pd.concat(axis=1) instead. To get a de-fragmented frame, use `newframe = frame.copy()`
  Firm_copy.insert(Firm_copy.columns.get_loc('Revenue'),'Revenue_Log', series_Revenue_Log)
C:\Users\ASUS\AppData\Local\Temp\ipykernel_17316\1464358194.py:51: PerformanceWarning: DataFrame is highly fragmented.  This is usually the result of calling `frame.insert` many times, which has poor performance.  Consider joining all columns at once using pd.concat(axis=1) instead. To get a de-fragmented frame, use `newframe = frame.copy()`
  Firm_copy.insert(Firm_copy.columns.get_loc('Num_Employ'),'Num_Employ_Log', series_Num_Employ_Log)
In [5]:
# visualization
pos = nx.nx_agraph.graphviz_layout(G, prog="twopi", args="")
dict_num_firm = nx.get_node_attributes(G, 'Num_Firm')
dict_node_name = nx.get_node_attributes(G, 'Name')
node_labels = {}
for node in nx.nodes(G):
    node_labels[node] = f"{node} {str(dict_node_name[node])} {str(dict_num_firm[node])}"
    # node_labels[node] = f"{str(dict_num_firm[node])}"
plt.figure(figsize=(12, 12), dpi=300)
nx.draw_networkx_nodes(G, pos)
nx.draw_networkx_edges(G, pos)
nx.draw_networkx_labels(G, pos, labels = node_labels, font_size=4)
plt.show()
In [3]:
import seaborn as sns
data = Firm_copy[Firm_copy['Num_Employ'] > 0]['Num_Employ']
print(data)
sns.displot(data)
Out [3]:
0       7393.0
1        171.0
2        113.0
3         24.0
4        242.0
        ...   
165       60.0
166      292.0
167    13371.0
168     5057.0
169     5173.0
Name: Num_Employ, Length: 129, dtype: float64
<seaborn.axisgrid.FacetGrid at 0x2bd702fc820>
In [4]:
import seaborn as sns
data = Firm_copy[Firm_copy['Revenue'] > 0]['Revenue']
print(data)
sns.displot(data)
Out [4]:
0      1.089000e+10
1      1.380000e+08
6      1.590000e+08
11     6.750000e+08
13     2.470000e+09
           ...     
162    5.880760e+07
167    4.110000e+10
168    4.519000e+09
169    3.470400e+10
170    1.000000e+08
Name: Revenue, Length: 111, dtype: float64
<seaborn.axisgrid.FacetGrid at 0x2bd17758a00>
In [ ]: