Unveiling the Aftermath using Network Analytics: How Russia-Ukraine War Reshapes World Trade?

Jirattiporn Siritirawat
10 min readMay 9, 2023

--

Source: UNCTAD secretariat calculations based on COMTRADE and UNCTADStat data.

เทรนด์มูลค่าการค้า (Trade Value) ของโลกมีแนวโน้มที่จะเพิ่มสูงขึ้นเรื่อย ๆ ทั้งในส่วนของการค้าสินค้าและบริการ อันเนื่องมาจากผลกระทบเชิงบวกจาก Globalization ที่ส่งผลต่อการขยายกิจกรรมทางเศรษฐกิจระหว่างประเทศในด้านต่าง ๆ

อย่างไรก็ตาม การค้าระหว่างประเทศจะได้รับผลกระทบอย่างชัดเจนเมื่อเกิดเหตุการณ์บางอย่างที่กระทบต่อภาคเศรษฐกิจ โดยเฉพาะ Supply Chain ซึ่งสามารถวัดได้ด้วยการเปลี่ยนแปลงของมูลค่าการค้า และรวมถึงคู่ค้าของแต่ละประเทศด้วย

Global Financial Crisis ซึ่งเริ่มต้นขึ้นในปี 2008 ทำให้การส่งออกโลกในปี 2009 ลดลง 20% โดยประมาณ

COVID-19 pandemic ส่งผลให้การส่งออกของโลกลดลงราว ๆ 7%

แล้วสงคราม Russia-Ukraine ส่งผลกระทบอย่างไรต่อ World Trade ?

Source: THE STANDARD

เมื่อวันที่ 24 กุมภาพันธ์ 2022 Russia เริ่มเปิดฉากบุก Ukraine อย่างเต็มรูปแบบ จากนั้นจึงเริ่มยึดเมืองต่าง ๆ ใน Ukraine ซึ่งรวมถึงเมืองท่า Mariupol ที่มีความสำคัญทางยุทธศาสตร์ในการเชื่อมต่อทางการค้าด้วย

การกระทำของ Russia ส่งผลทำให้ราคาพลังงานเพิ่มสูงขึ้น เนื่องจากชาติตะวันตกคว่ำบาตรการส่งออกน้ำมันของ Russia และ EU ยังนำเข้าก๊าซธรรมชาติราว ๆ 40% จากท่อส่งของ Russia ซึ่งประมาณ 1 ใน 4 ของก๊าซธรรมชาตินั้นจำเป็นต้องไหลผ่านท่อใน Ukraine อีกทั้งราคาอาหารก็พุ่งสูงขึ้นทั่วโลก เพราะ Ukraine เป็นผู้ส่งออกธัญพืชหลักของโลก

นอกจากสงคราม Russia-Ukraine จะส่งผลกระทบหลักต่ออุตสาหกรรมพลังงานแล้ว ความขัดแย้งในครั้งนี้ก็ยังส่งผลต่ออุตสาหกรรม Semiconductor ที่ทำให้มีราคาสูงขึ้นและส่งผลต่อ Supply Chain เพราะวัตถุดิบเฉพาะ (Neon และ Palladium) ที่ใช้ในการผลิต Semiconductor นั้นมีแหล่งใหญ่อยู่ใน Russia และ Ukraine

ผลกระทบต่ออุตสาหกรรม Semiconductor ส่งผลต่อเนื่องไปยัง Sector ยานยนต์ เนื่องจากทำให้ไม่สามารถผลิตชิ้นส่วนบางอย่างได้ รวมถึงการขาดแคลนชุดสายไฟจาก Ukraine และการขาดแคลน Palladium ที่ใช้ในระบบท่อไอเสียรถยนต์จาก Russia

ปัจจัยเหล่านี้อาจทำให้เส้นทางการค้าเปลี่ยนแปลงไป ซึ่งอาจเป็นประโยชน์ต่อบางประเทศ แต่ส่งผลทางลบต่อบางประเทศเช่นกัน

ต่อมา เราจะมาดูกันว่าเราจะใช้ข้อมูลอะไร ? วิธีไหน ? ในการดูผลกระทบที่เกิดขึ้นจากสงคราม Russia-Ukraine

Get Trade Data from UN Comtrade for FREE!

UN Comtrade database เป็นแพลตฟอร์มข้อมูลการค้าที่ครอบคลุมมากที่สุดในโลก โดยฐานข้อมูลนี้จะรวบรวมสถิติการค้าทั่วโลก ทั้งรายปีและรายเดือน ซึ่งจะมีการเก็บข้อมูลแยกตามประเภทสินค้า (HS-Code) และแยกตามประเทศคู่ค้า โดยสามารถ download ข้อมูลที่ต้องการได้จาก UN Comtrade web page

แต่ถ้าอยาก download ข้อมูลสินค้าหลาย Sector หลายประเทศ หลายช่วงเวลาจะทำอย่างไรล่ะ ?

สามารถทำได้โดยการดึงข้อมูลผ่าน UN Comtrade Data API ได้เลย!

เริ่มต้นจากการ Set ค่าเริ่มต้นว่าต้องการข้อมูลแบบไหนก่อน โดยเราจะใช้เป็นข้อมูลรายเดือน และจะ Download ข้อมูลประเภท Import และ Export แยกกันอย่างละรอบ เพื่อให้ได้ข้อมูลที่ครบถ้วน

ซึ่งอาจต้องแบ่งการ Download ข้อมูลออกเป็นหลาย ๆ รอบ เนื่องจากข้อจำกัดของ UN Comtrade API โดยสามารถดูรายละเอียดเพิ่มเติมได้ที่ Free Access to UN Comtrade

import os
import requests
import time
# Annual Data
# url1 = 'https://comtrade.un.org/api/get?max=100000&type=C&freq=A&px=HS&'

# Monthly Data
url1 = 'https://comtrade.un.org/api/get?max=100000&type=C&freq=M&px=HS&'

# Export Data
label = 'X'
url2 = '&p=all&rg=2&cc='

# Import Data
# label = 'M'
# url2 = '&p=all&rg=1&cc='

# ใส่ Token ของเราลงไป
url3 = '&uitoken=...'

# กำหนดปีที่เราต้องการข้อมูล
period = 'ps=2015'
yr = '2015'

# ใส่รหัสประเทศที่เราต้องการข้อมูลลงไป
reporters = [458, 554, 608, 643, 699, 702, 704]

# ใส่ HS-code ที่เราต้องการ
HS_code = [2709, 2711, 3002, 7108, 8541, 8703, 9020]

โดยรหัสของแต่ประเทศสามารถดูได้จาก Comtrade Country Code and Name

ไป Download ข้อมูลกันเลย!

# เปลี่ยน Working Directory ของเราให้ตรงตาม Folder ที่จะเก็บข้อมูลไว้ โดยแนะนำให้เก็บข้อมูลแยกเป็นปี
os.chdir('...')

lastime = time.perf_counter()
for i in range(0, len(reporters)):
rcode = str(reporters[i])
for j in range(0,len(HS_code)):
HS = str(HS_code[j])
url = url1 + period + '&r=' + rcode + url2 + HS + url3 + '&fmt=csv'
thistime = time.perf_counter()
timeused = thistime - lastime
lasttime = thistime
if timeused <= 1:
time.sleep(1-timeused)
r = requests.get(url, allow_redirects=True)
if len(r.content) == 72:
time.sleep(1)
r = requests.get(url, allow_redirects=True)
if len(r.content) > 2000:
open( rcode + label + '-' + HS + '-' + yr + '.csv', 'wb').write(r.content)
elif len(r.content) != 611:
print(rcode, len(r.content))
print(r.content.decode(r.encoding,'ignore'))
if len(r.content) == 230:
break

ตัวอย่างข้อมูลที่ได้:

Let’s visualize Network indicators and trade networks!

ขั้นตอนแรกเราจะ Import Package และสร้าง Function, Dictionary ที่ต้องใช้ก่อน

import os
import pandas as pd
import numpy as np
import networkx as nx
import seaborn as sns
import matplotlib.pyplot as plt
import matplotlib.ticker as ticker
from matplotlib.axis import Axis
from scipy.sparse.csgraph import minimum_spanning_tree
# สร้าง Function สำหรับ Import ข้อมูลและ Drop Column ที่ไม่ได้ใช้

def im_dropcol(reporters, years, HS):

df_all = []
df_TT_all = []

for yr in years:
os.chdir(f'...\{yr}') # Working Directory
for i in reporters:
file_name1 = str(i) + 'X' + '-' + str(HS) + '-' + str(yr) + '.csv'
file_name2 = 'M' + str(i) + '-' + str(HS) + '-' + str(yr) + '.csv'
file_exists1 = os.path.exists(file_name1)
file_exists2 = os.path.exists(file_name2)
if file_exists1 == True:
globals()[f'df_{i}_{HS}_{yr}_bf'] = pd.read_csv(file_name1)
df_all.append(globals()[f'df_{i}_{HS}_{yr}_bf'])
globals()[f'df_{i}_{HS}_TT{yr}_bf'] = pd.read_csv(file_name1)
df_TT_all.append(globals()[f'df_{i}_{HS}_TT{yr}_bf'])
elif file_exists2 == True:
globals()[f'df_{i}_{HS}_{yr}_bf'] = pd.read_csv(file_name2)
df_all.append(globals()[f'df_{i}_{HS}_{yr}_bf'])
globals()[f'df_{i}_{HS}_TT{yr}_bf'] = pd.read_csv(file_name2)
df_TT_all.append(globals()[f'df_{i}_{HS}_TT{yr}_bf'])
elif file_exists1 == False and file_exists2 == False:
continue

# Drop Unused Columns
columns_to_drop = ['Classification', 'Year', 'Period Desc.', 'Aggregate Level', 'Is Leaf Code', 'Trade Flow Code',
'Reporter ISO', 'Partner ISO', '2nd Partner Code', '2nd Partner', '2nd Partner ISO', 'Customs Proc. Code',
'Customs', 'Mode of Transport Code', 'Mode of Transport', 'Commodity Code', 'Commodity', 'Qty Unit Code', 'Qty Unit',
'Qty', 'Alt Qty Unit Code', 'Alt Qty Unit', 'Alt Qty', 'Netweight (kg)', 'Gross weight (kg)', 'CIF Trade Value (US$)',
'FOB Trade Value (US$)', 'Flag']

for i in df_all + df_TT_all:
i.drop(columns_to_drop, axis=1, inplace=True)


return df_all, df_TT_all
# สร้าง function สำหรับการ clean ข้อมูล

def data_clean(df_all, df_TT_all, periods, percentile):

# filter period
for df in [df_all, df_TT_all]:
for i in df:
i.drop(i[-i['Period'].isin(periods)].index, inplace=True)

# filter countries
for i in df_all:
if i['Trade Flow'].unique() == 'Imports':
i.drop(i[-i['Reporter Code'].isin(reporters)].index, inplace=True)
else:
i.drop(i[-i['Partner Code'].isin(reporters)].index, inplace=True)

for i in df_TT_all:
if i['Trade Flow'].unique() == 'Imports':
i.drop(i[(i['Reporter Code'] == 97) | (i['Reporter Code'] == 975)].index, inplace=True)
else:
i.drop(i[(i['Partner Code'] == 0)].index, inplace=True)

for df in [df_all, df_TT_all]:
# switch column
for i in df:
if i['Trade Flow'].unique() == 'Imports':
i.rename(columns={'Reporter Code':'Partner Code', 'Reporter':'Partner',
'Partner Code':'Reporter Code', 'Partner':'Reporter'}, inplace=True)

# rename column
for i in df:
i.rename(columns={'Trade Value (US$)':'TV', 'Reporter Code':'Exporter', 'Partner Code':'Importer'}, inplace=True)

# drop unused columns
for i in df:
i.drop(['Trade Flow','Reporter','Partner'], axis=1, inplace=True)

# concat table
df = pd.concat(df_all)
df_TT = pd.concat(df_TT_all)

# rename countries
df = df.replace({'Brunei Darussalam': 'Brunei', 'United States of America': 'USA',
'Rep. of Korea': 'Korea', 'Russian Federation': 'Russia',
'United Arab Emirates': 'Emirates', "Lao People's Dem. Rep.": "Laos",
'United Kingdom': 'UK'})
df_TT = df_TT.replace({'Brunei Darussalam': 'Brunei', 'United States of America': 'USA',
'Rep. of Korea': 'Korea', 'Russian Federation': 'Russia',
'United Arab Emirates': 'Emirates', "Lao People's Dem. Rep.": "Laos",
'United Kingdom': 'UK'})

# standardize
df['TV'] = df['TV'] / df_TT['TV'].sum()

# filter เอาแค่ที่ trade value > percentile ที่กำหนดไว้
# filter ให้เหลือแต่คู่ประเทศที่ trade กันค่อนข้างเยอะ เพื่อให้เห็นความชัดเจนมากขึ้น
# เลือก percentile จาก percentile ที่ทำให้ได้ Minimum Spanning Tree คล้าย ๆ กันในหลาย ๆ algorithm
df = df[df['TV'] > np.percentile(df['TV'], percentile)]

return df
# สร้าง Dict ชื่อประเทศเพื่อให้ง่ายต่อการ Visualize ในภายหลัง

ctrys_codetoname = pd.read_csv('reportersAreas.csv', skiprows=[1])
ctrys_codetoname = ctrys_codetoname.rename(columns={'id': 'Exporter'}).replace({
'Brunei Darussalam': 'Brunei',
'United States of America': 'USA',
'Rep. of Korea': 'Korea',
'Russian Federation': 'Russia',
'United Arab Emirates': 'Emirates',
"Lao People's Dem. Rep.": 'Laos',
'United Kingdom': 'UK'
})

ctrys_codetoname_dict = dict(zip(ctrys_codetoname['Exporter'], ctrys_codetoname['text']))

เริ่มกันเลย!

อย่างแรก เราจะ Plot Network Indicator เพื่อดูการเปลี่ยนแปลงในแต่ละช่วงเวลา โดยต้องกำหนดประเทศ (reporters) ปี (years) และ Sector สินค้า (HS) ที่สนใจก่อน และจึง Import ข้อมูลเข้ามา

reporters = [36, 96, 104, 116, 124, 156, 276, 360, 392, 410, 418, 
458, 554, 608, 643, 682, 699, 702, 704, 764, 784, 842]

years = list(range(2015,2023))

sectorname = '27.09 Petroleum oils'
HS = 2709

df_all, df_TT_all = im_dropcol(reporters, years, HS)

จากนั้นก็ Clean Data ให้อยู่ในช่วงเวลาและรูปแบบที่เราต้องการ

periods = list(range(201501,201513)) + list(range(201601,201613)) + list(range(201701,201713)) + \
list(range(201801,201813)) + list(range(201901,201913)) + list(range(202001,202013)) + \
list(range(202101,202113)) + list(range(202201,202206))

df = data_clean(df_all, df_TT_all, periods, 60).replace(ctrys_codetoname_dict)
df.head()

Split Dataframe ออกเป็นกลุ่ม โดยแบ่งตามปีเดือน

grouped = df.groupby(df.Period)
for i in periods:
try:
globals()[f'df_{i}'] = grouped.get_group(i)
except:
pass

df_all_period = []
for i in periods:
try:
df_all_period.append(globals()[f'df_{i}'])
except:
pass

# Directed Graph for Out-degree Centrality Calculation
for i,j in zip(periods,df_all_period):
globals()[f'G_{i}_di'] = nx.from_pandas_edgelist(j, source='Exporter', target='Importer',
edge_attr='TV', create_using=nx.DiGraph)

# Undirected Graph for Betweenness Centrality Calculation
for i,j in zip(periods,df_all_period):
globals()[f'G_{i}_undi'] = nx.from_pandas_edgelist(j, source='Exporter', target='Importer',
edge_attr='TV')

จากนั้นจึงสร้าง Network Graph เพื่อใช้คำนวน Network Indicator โดยในที่นี้จะเลือกพิจารณา 2 อย่าง คือ Out-degree Centrality และ Betweenness Centrality ซึ่งสามารถบอกถึงความสำคัญของประเทศหนึ่ง ๆ ต่อ Trade Network ในแต่ละ Sector สินค้าได้

Source: Quantifying a Systems Map: Network Analysis of a Childhood Obesity Causal Loop Diagram
# Calulate Out-degree Centrality
for i in periods:
globals()[f'degree_dict_{i}'] = dict(globals()[f'G_{i}_di'].degree(globals()[f'G_{i}_di'].nodes()))

# Change Dict Key
country_list = df['Exporter'].values.tolist() + df['Importer'].values.tolist()
country_list = [*set(country_list)]

for i in periods:
for j in country_list:
try:
globals()[f'degree_dict_{i}'][f'{j}_{i}'] = globals()[f'degree_dict_{i}'].pop(f'{j}')
except:
pass

# Concatenate Dict
degree_dict_all = {}

for i in periods:
degree_dict_all.update(globals()[f'degree_dict_{i}'])

# Convert Dict to df
degree_df = pd.DataFrame(degree_dict_all, index=[0])
degree_df = degree_df.transpose().reset_index()
degree_df.rename(columns={'index':'country_time', 0:'degree'},inplace=True)
degree_df[['country','t']] = degree_df['country_time'].str.split('_', expand=True)
degree_df.drop(['country_time'], axis=1, inplace=True)

# Convert Date
degree_df['t'] = pd.to_datetime(degree_df['t'], format='%Y%m').dt.strftime("%Y-%m")
degree_df.head()
# Calculate Betweenness Centrality
for i in periods:
globals()[f'betweenness_dict_{i}'] = dict(nx.betweenness_centrality(globals()[f'G_{i}_undi']))

# Change Dict Key
for i in periods:
for j in country_list:
try:
globals()[f'betweenness_dict_{i}'][f'{j}_{i}'] = globals()[f'betweenness_dict_{i}'].pop(f'{j}')
except:
pass

# Concatenate Dict
betweenness_dict_all = {}
for i in periods:
betweenness_dict_all.update(globals()[f'betweenness_dict_{i}'])

# Convert Dict to df
betweenness_df = pd.DataFrame(betweenness_dict_all, index=[0])
betweenness_df = betweenness_df.transpose().reset_index()
betweenness_df.rename(columns={'index':'country_time', 0:'betweenness'},inplace=True)
betweenness_df[['country','t']] = betweenness_df['country_time'].str.split('_', expand=True)
betweenness_df.drop(['country_time'], axis=1, inplace=True)

# Convert Date
betweenness_df['t'] = pd.to_datetime(betweenness_df['t'], format='%Y%m').dt.strftime("%Y-%m")
betweenness_df.head()

จากนั้น Filter ประเทศที่เราสนใจ เช่น Russia ซึ่งเป็นผู้ส่งออกน้ำมันรายใหญ่ของโลก โดยเราจะมีการทำ Moving Average 12 เดือนเพื่อกำจัดปัญหา Seasonal Effect และเพื่อให้ Graph มีความ Smooth มากขึ้น

degree_df_russia = degree_df[degree_df['country'] == 'Russia']

# Moving Average
degree_df_russia['degree'] = degree_df_russia['degree'].rolling(12, min_periods=1).mean()
degree_df_russia.head()
sns.set_style('darkgrid')
sns.set(rc={'figure.figsize':(17,4)})

ax = sns.lineplot(data=degree_df_russia[12:], x ='t', y = 'degree', legend='full', lw=3)
ax.xaxis.set_major_locator(ticker.MultipleLocator(5))

country = 'Russia'

plt.axvline(x='2022-02',color='r',ls='--',lw=3) # Russia-Ukraine War
plt.title(f'{country}: {sectorname} - Out-degree Centrality', size=15, weight='bold')
plt.ylabel('Degree Centrality')
plt.xlabel('t')
plt.show()
betweenness_df_russia = betweenness_df[betweenness_df['country'] == 'Russia']

# Moving Average
betweenness_df_russia['betweenness'] = betweenness_df_russia['betweenness'].rolling(12, min_periods=1).mean()
betweenness_df_russia.head()
sns.set_style('darkgrid')
sns.set(rc={'figure.figsize':(17,4)})

ax = sns.lineplot(data=betweenness_df_russia[12:], x ='t', y = 'betweenness', legend='full', lw=3)
ax.xaxis.set_major_locator(ticker.MultipleLocator(5))

plt.axvline(x='2022-02',color='r',ls='--',lw=3)# Russia-Ukraine War
plt.title(f'{country}: {sectorname} - Betweenness Centrality', size=15, weight='bold')
plt.ylabel('Betweenness Centrality')
plt.xlabel('t')
plt.show()

เห็นการเปลี่ยนแปลงหลังการเกิดสงครามหรือเปล่า ?

เพื่อเป็นการยืนยัน เราจะเจาะลึกลงไปดูอีกเพื่อให้เห็นว่ามันเกิดอะไรขึ้น โดยการ Plot Trade Network

เริ่มจากการ Import ข้อมูลเข้ามาเหมือนเดิม แต่คราวนี้เราจะแบ่งช่วงเวลาออกเป็น “ก่อน” (ปีปกติ) และ “หลัง” การเกิดสงคราม

reporters = [36, 96, 104, 116, 124, 156, 276, 360, 392, 410, 418, 
458, 554, 608, 643, 682, 699, 702, 704, 764, 784, 842]
years = list(range(2015,2023))
HS = 2709

df_all_bf, df_TT_all_bf = im_dropcol(reporters, years, HS)

df_all_af, df_TT_all_af = im_dropcol(reporters, years, HS)

Clean Data และทำการหาค่าเฉลี่ยของมูลค่าการค้าในช่วงเวลาที่พิจารณา

# ก่อนการเกิดสงคราม Russia-Ukraine: Mar 2016 - May 2016

periods_Benchmark = list(range(201603,201606))

df_bf = data_clean(df_all_bf, df_TT_all_bf, periods_Benchmark, 60).replace(ctrys_codetoname_dict)
df_bf = df_bf.groupby(['Exporter', 'Importer']).agg({'TV': 'mean'}).reset_index()
df_bf.head()
# หลังการเกิดสงคราม Russia-Ukraine: Mar 2022 - May 2022

periods_After = list(range(202203,202206))

df_af = af_data_clean(df_all_af, df_TT_all_af, periods_After).replace(ctrys_codetoname_dict)
df_af = df_af.groupby(['Exporter', 'Importer']).agg({'TV': 'mean'}).reset_index()
df_af.head()

# note: สามารถปรับขนาดของมูลค่าการค้าได้เพื่อความเหมาะสมในการ Visualize เช่น การคูณด้วย 1000

เช่นเดิม เราจะ Filter ประเทศที่เราสนใจและ Plot Trade Network ออกมา และเราจะกำหนดให้ความหนาของลูกศรแสดงถึงมูลค่าการส่งออกจากประเทศ Node ตรงกลางไปยังประเทศ Node โดยรอบ โดยถ้าลูกศรหนามาก แปลว่าส่งออกไปประเทศนั้นมาก

df_bf_russia = df_bf[df_bf['Exporter'] == 'Russia']

G_bf_russia = nx.from_pandas_edgelist(df_bf_russia,source='Exporter',target='Importer',edge_attr='TV')
fig, ax = plt.subplots(figsize=(10, 7))
widths_bf_russia = nx.get_edge_attributes(G_bf_russia, 'TV')
bf_title = 'Before Russia-Ukraine War: Mar 2016 - May 2016'
plt.title(f'{sectorname} - {bf_title}')

# ทำเพื่อปรับขนาดหัวลูกศรให้มีความเหมาะสมมากขึ้น
ws = []
for edge in G_bf_russia.edges(data=True):
w = edge[2]['TV'] + 55
ws.append(w)

nx.draw(G_bf_russia, arrows=True, arrowstyle='-|>', with_labels=True, node_size=700, width=list(widths_bf_russia.values()),
font_weight='bold', font_family='serif', font_size=18, edge_color='gray', arrowsize=ws)
df_af_russia = df_af[df_af['Exporter'] == 'Russia']

G_af_russia = nx.from_pandas_edgelist(df_af_russia,source='Exporter',target='Importer',edge_attr='TV')
fig, ax = plt.subplots(figsize=(10, 7))
widths_af_russia = nx.get_edge_attributes(G_af_russia, 'TV')
af_title = 'After Russia-Ukraine War: Mar 2022 - May 2022'
plt.title(f'{sectorname} - {af_title}')

ws = []
for edge in G_af_russia.edges(data=True):
w = edge[2]['TV'] + 40
ws.append(w)

nx.draw(G_af_russia, arrows=True, arrowstyle='-|>', with_labels=True, node_size=700, width=list(widths_af_russia.values()),
font_weight='bold', font_family='serif', font_size=18, edge_color='gray', arrowsize=ws)

สุดท้าย เพื่อเจาะดูการเปลี่ยนแปลงของ Betweenness Centrality เราจะทำ Minimum Spanning Tree (MST) ซึ่งจะช่วยลดความซับซ้อนของ Network โดยที่ยังเหลือโครงสร้างที่จำเป็นอยู่ ทำให้สามารถรู้ได้ว่าประเทศไหนมีความสำคัญในการค้าสินค้า Sector นั้น ๆ

Source: Stuart Mashaal

โดย MST จะเชื่อมต่อ Node ทั้งหมดของ Network ที่ให้น้ำหนักรวมที่น้อยที่สุดเท่าที่จะเป็นไปได้ โดยถ้าหาก Node ใดเชื่อมต่อกับ Node อื่น ๆ หลาย Node ก็จะแสดงว่า Node นั้นสามารถส่งผลกระทบต่อ Node อื่นได้มาก กล่าวคือ มีอิทธิพลต่อ Node อื่นนั่นเอง

# Trade Network ต้นฉบับ
G_bf = nx.from_pandas_edgelist(df_bf,source='Exporter',target='Importer', edge_attr=True)

# MST before the war
algo = 'prim'
G_mst_bf = nx.minimum_spanning_tree(G_bf, algorithm=algo)
fig, ax = plt.subplots(figsize=(10, 7))
plt.title(f'MST {sectorname} - {bf_title}')
nx.draw(G_mst_bf, with_labels=True, node_size=500,
font_weight='bold', font_family='serif',
font_size=12, edge_color='gray')
# MST after the war
G_af = nx.from_pandas_edgelist(df_af,source='Exporter',target='Importer', edge_attr=True)
G_mst_af = nx.minimum_spanning_tree(G_af, algorithm=algo)

fig, ax = plt.subplots(figsize=(10, 7))
plt.title(f'MST {sectorname} - {af_title}')
nx.draw(G_mst_af, with_labels=True, node_size=500,
font_weight='bold', font_family='serif',
font_size=12, edge_color='gray')

เห็นอะไรบ้าง ?

Petroleum Oils

จาก Graph ของ Russia ที่ผ่านมา เมื่อเปรียบเทียบปีปกติ (Mar 2016 — May 2016) กับปีหลังเกิดสงคราม (Mar 2022 — May 2022) แล้วพบว่าหลังสงคราม Russia มี Out-degree Centrality สูงกว่า ในขณะที่ Trade Network มีจำนวนคู่ค้าเท่าเดิม แต่ก็จะเห็นได้ว่า Russia มีประเทศคู่ค้าที่เปลี่ยนไป แสดงให้เห็นถึงโอกาสที่มากขึ้นในการเข้าถึงคู่ค้ารายใหม่ อีกทั้งมูลค่าการค้าโดยรวมก็เพิ่มขึ้น โดยเฉพาะกับประเทศคู่ค้าที่มีอยู่เดิมแล้ว คือ Germany และ China ซึ่งจีนต้องการช่วยต่อชีวิตทางการเงินให้กับรัฐบาล Russia ที่ได้รับผลกระทบจากมาตรการคว่ำบาตรของ EU

Emirates — Petroleum Oils

ในขณะที่ Emirates ซึ่งไม่ได้ออกมาคว่ำบาตร Russia หรือวิจารณ์การรุกราน Ukraine แต่อย่างใดนั้น มีคู่ค้าน้ำมันลดลงภายหลังการเกิดสงคราม ซึ่งสอดคล้องกับ Out-degree Centrality ที่ลดลง อีกทั้ง China ก็ได้รับผลกระทบเชิงลบในด้านของการค้าเช่นเดียวกัน

USA — Petroleum Oils

USA กลับได้รับประโยชน์จากการคว่ำบาตรของยุโรป จะเห็นได้ว่า USA มีมูลค่าการค้าและคู่ค้าน้ำมันที่เพิ่มขึ้น ซึ่งเป็นไปในทิศทางเดียวกันการเพิ่มขึ้นของ Out-degree Centrality รวมถึง Canada เองก็ได้รับผลประโยชน์ทางการค้าเช่นเดียวกัน

Minimum Spanning Tree — Petroleum Oils

จะเห็นได้ว่าภายหลังการเกิดสงคราม USA มีอิทธิพลต่อประเทศอื่นในเครือข่ายการค้าน้ำมันมากกว่าช่วงก่อนเกิดสงคราม สอดคล้องกับ Betweenness Centrality ที่เพิ่มขึ้น ในขณะที่ Emirates มีประเทศที่เชื่อมต่อด้วยน้อยลงอย่างชัดเจน ซึ่งเป็นไปในทิศทางเดียวกันกับการลดลงของ Betweenness Centrality อีกทั้งยังพบว่า Russia เชื่อมต่อกับจำนวนคู่ค้าเท่าเดิม แต่เปลี่ยนไปเป็นเชื่อมกับ China แทน ส่วน Canada นั้นไม่มีการเปลี่ยนแปลง ยังคงเชื่อมต่อกับ USA เพียงประเทศเดียวเหมือนเดิม

Semiconductor

Singapore — Semiconductor

ถึงแม้ Singapore จะมีจุดยืนชัดเจนว่าอยู่ฝั่ง Ukraine แต่หลังการเกิดสงคราม Singapore มีจำนวนคู่ค้าใน Sector Semiconductor ลดลงอย่างเห็นได้ชัด ซึ่งสอดคล้องกับแนวโน้มการลดลงของ Out-degree Centrality อีกทั้งก็ยังมีประเทศอื่นที่ร่วมคว่ำบาตร Russia แต่ได้รับผลกระทบเชิงลบในการค้าใน Sector นี้ด้วย เช่น (South) Korea และ Japan หรือแม้กระทั่ง Emirates เองก็ยังมีคู่ค้า Semiconductor ที่ลดลงเช่นกัน

Russia — Semiconductor

ในทางกลับกัน Russia มีคู่ค้า Semiconductor เพิ่มขึ้น ซึ่งเป็นไปในทิศทางเดียวกันกับการเปลี่ยนแปลงของ Out-degree Centrality แต่เป็นการเพิ่มขึ้นเพียง 1 ประเทศเท่านั้น อีกทั้งยังไม่พบการเพิ่มขึ้นของมูลค่าการค้า นอกจากนี้ อีก 1 ประเทศที่ได้รับผลกระทบทางบวก คือ USA แต่เป็นการเพิ่มขึ้นของคู่ค้าเพียง 1 ประเทศและมูลค่าการค้าก็ไม่เปลี่ยนแปลงมากนัก

Minimum Spanning Tree — Semiconductor

พบว่าหลังสงคราม Russia-Ukraine เครือข่ายการค้า Semiconductor มีการกระจายตัวมากขึ้น โดย Singapore มีอิทธิพลต่อประเทศอื่นน้อยลงสอดคล้องกับเทรนด์ของ Betweenness Centrality ที่ลดลง ซึ่งรวมถึง Japan, Korea และ Emirates ด้วย ในขณะที่ Betweenness Centrality ของ Russia และ USA มีการเปลี่ยนแปลงไม่มากนัก แต่ในภาพของ MST จะพบได้ว่า 2 ประเทศนี้เชื่อมต่อกับประเทศอื่นน้อยลง

Motor Cars

Germany — Motor cars

Germany ซึ่งเป็นผู้ผลิตรถอันดับ 1 ของโลกได้รับผลกระทบเล็กน้อยจากสงคราม Russia-Ukraine คือ มีคู่ค้าลดลง สอดคล้องกับ Out-degree Centrality ที่ลดลงไม่มากนักเมื่อเปรียบเทียบกับปีปกติ รวมถึง Japan, USA และ Canada ด้วย ในขณะที่ Korea และ Thailand กลับโดนผลกระทบจากการเกิดสงครามค่อนข้างเยอะ โดยเฉพาะในด้านของจำนวนคู่ค้า ถึงแม้ว่า 2 ประเทศนี้จะขึ้นชื่อว่าเป็นผู้ส่งออกรถยนต์หลักก็ตาม ส่วน Russia ที่ไม่ได้ส่งออกรถยนต์มากนักก็ได้รับผลกระทบทางลบตามทิศทางของ Out-degree Centrality เช่นกัน

USA— Motor cars

USA เป็นเพียงประเทศเดียวที่ภายหลังสงครามมี Out-degree Centrality เพิ่มขึ้น แต่เป็นการเพิ่มขึ้นเล็กน้อยเท่านั้น และเมื่อพิจารณา Trade Network จะเห็นได้ว่า USA มีคู่ค้าใน Sector Motor Cars ที่ลดลง ในขณะที่มูลค่าการค้าไม่เปลี่ยนแปลงมากนัก

Minimum Spanning Tree — Motor cars

เห็นได้ว่า Germany เชื่อมต่อกับประเทศอื่นน้อยลง โดย Japan, Korea และ Thailand เปลี่ยนแปลงไปในทิศทางเดียวกันกับ Germany สอดคล้องกับการลดลงของ Betweenness Centrality ของแต่ละประเทศ ในขณะที่ Canada และ Russia ไม่มีการเปลี่ยนแปลงมากนัก ส่วน USA ที่มีการเพิ่มขึ้นของ Betweenness Centrality เล็กน้อย แต่ในภาพของ MST กลับบอกว่า USA มีอิทธิพลต่อเครือข่ายการค้ารถยนต์น้อยลงภายหลังการเกิดสงคราม Russia-Ukraine

In summary

--

--