คลิกเพื่อดูโค้ดไพธอน
import pandas as pd
from IPython.display import display
df = pd.DataFrame({
"year": [2018, 2019, 2020, 2021],
"gdp": [500, None, 480, 510]
})
display(df)| year | gdp | |
|---|---|---|
| 0 | 2018 | 500.0 |
| 1 | 2019 | NaN |
| 2 | 2020 | 480.0 |
| 3 | 2021 | 510.0 |
Python for Economics, Computational Economics, Applied Econometrics, Python สำหรับเศรษฐศาสตร์, เศรษฐศาสตร์คำนวณ, เศรษฐมิติเชิงประยุกต์
ในงานเศรษฐศาสตร์ เราไม่ได้เจอแค่ตัวเลขดิบๆ แต่เราเจอข้อมูลที่มีโครงสร้างเฉพาะตัว Pandas จึงออกแบบมาเพื่อจัดการกับข้อมูล 3 ประเภทหลักที่นักเศรษฐศาสตร์ต้องเจออยู่เสมอ ได้แก่ Cross-sectional, Time Series, และ Panel Data
ในบทก่อนหน้า เราได้ใช้ข้อมูลจำลองเพื่อทำความเข้าใจแนวคิดทางเศรษฐศาสตร์และการคำนวณเชิงเมทริกซ์
อย่างไรก็ตาม ในโลกจริง นักเศรษฐศาสตร์ไม่ได้ทำงานกับข้อมูลที่ “พร้อมใช้งาน” ตั้งแต่ต้น
ข้อมูลทางเศรษฐศาสตร์มักมีลักษณะดังนี้:
มีขนาดใหญ่ (หลายพันถึงหลายล้านแถว)
มาจากหลายแหล่งข้อมูล
มีค่าที่หายไป (missing values)
มีรูปแบบที่ไม่สม่ำเสมอ
ตัวอย่างเช่น:
ข้อมูล GDP จากหลายประเทศ
ข้อมูลรายได้ของประชากร
ข้อมูลตลาดการเงินรายวัน
import pandas as pd
from IPython.display import display
df = pd.DataFrame({
"year": [2018, 2019, 2020, 2021],
"gdp": [500, None, 480, 510]
})
display(df)| year | gdp | |
|---|---|---|
| 0 | 2018 | 500.0 |
| 1 | 2019 | NaN |
| 2 | 2020 | 480.0 |
| 3 | 2021 | 510.0 |
จากตัวอย่างนี้จะเห็นว่า:
มีค่าที่หายไป (NaN)
ข้อมูลยังไม่พร้อมสำหรับการวิเคราะห์
ก่อนที่ข้อมูลจะถูกนำไปวิเคราะห์หรือสร้างแบบจำลอง นักเศรษฐศาสตร์ต้องจัดการข้อมูลให้อยู่ในรูปแบบที่เหมาะสม กระบวนการนี้เรียกว่า Data Wrangling หรือการเตรียมข้อมูลเพื่อการวิเคราะห์
ตรวจสอบข้อมูล (explore)
ทำความสะอาดข้อมูล (clean)
แปลงข้อมูลให้อยู่ในรูปแบบที่เหมาะสม (transform)
flowchart TD
A[นำเข้าข้อมูล<br/>Import Data] --> B[ตรวจสอบข้อมูล<br/>Inspect Data]
B --> C[ทำความสะอาดข้อมูล<br/>Clean Data]
C --> D[แปลงรูปแบบข้อมูล<br/>Transform Data]
D --> E[สรุปและวิเคราะห์เบื้องต้น<br/>Summarize Data]
E --> F[สร้างกราฟหรือแบบจำลอง<br/>Visualize / Model]
จากหัวข้อก่อนหน้า เราได้เห็นว่า ข้อมูลทางเศรษฐศาสตร์ในโลกจริงมักไม่พร้อมใช้งานทันที ดังนั้น นักเศรษฐศาสตร์จำเป็นต้องมีเครื่องมือสำหรับ “จัดการข้อมูล” ก่อนนำไปวิเคราะห์
Pandas คือเครื่องมือหลักใน Python สำหรับงานนี้ ดังนั้นในกระบวนการจัดการข้อมูล
NumPy → ใช้คำนวณเชิงตัวเลข
Pandas → ใช้จัดการข้อมูลเชิงตาราง
Pandas ทำหน้าที่เป็น “โต๊ะทำงานของข้อมูล” (data workspace)
Pandas มีโครงสร้างข้อมูลสำคัญ 2 แบบ:
Series → ข้อมูล 1 มิติ (คล้าย vector)
DataFrame → ข้อมูล 2 มิติ (คล้ายตาราง)
ตัวอย่าง:
import pandas as pd
import numpy as np
# สร้าง DataFrame เบื้องต้น (Cross-sectional: ข้อมูล ณ จุดเวลาหนึ่ง)
data = {
'Country': ['Thailand', 'Vietnam', 'Singapore', 'Malaysia'],
'GDP_Growth': [2.5, 5.0, 1.2, 3.8],
'Inflation': [1.5, 3.2, 5.0, 2.1]
}
df = pd.DataFrame(data)
display(df)| Country | GDP_Growth | Inflation | |
|---|---|---|---|
| 0 | Thailand | 2.5 | 1.5 |
| 1 | Vietnam | 5.0 | 3.2 |
| 2 | Singapore | 1.2 | 5.0 |
| 3 | Malaysia | 3.8 | 2.1 |
DataFrame คือรูปแบบข้อมูลที่ใช้บ่อยที่สุดในงานเศรษฐศาสตร์
ในงานเศรษฐศาสตร์ ข้อมูลส่วนใหญ่จะอยู่ในรูปแบบ “ตาราง” เช่น:
ตาราง GDP ของหลายประเทศ
ตารางรายได้ของประชากร
ตารางข้อมูลตลาดการเงิน
ตัวอย่างเช่น:
| year | gdp | inflation |
|---|---|---|
| 2018 | 500 | 2.1 |
| 2019 | 520 | 2.5 |
| 2020 | 480 | 3.0 |
ข้อมูลลักษณะนี้คือสิ่งที่เราใช้วิเคราะห์จริง
ใน Pandas ตารางแบบนี้เรียกว่า DataFrame
แถว (rows) → observation
คอลัมน์ (columns) → ตัวแปร (variables)
ตัวอย่าง DataFrame
import pandas as pd
df = pd.DataFrame({
"year": [2018, 2019, 2020],
"gdp": [500, 520, 480],
"inflation": [2.1, 2.5, 3.0]
})
display(df)| year | gdp | inflation | |
|---|---|---|---|
| 0 | 2018 | 500 | 2.1 |
| 1 | 2019 | 520 | 2.5 |
| 2 | 2020 | 480 | 3.0 |
เราสามารถเลือกข้อมูลได้ง่าย เช่น:
เลือกตัวแปร GDP
df["gdp"]0 500
1 520
2 480
Name: gdp, dtype: int64
เลือกหลายตัวแปร
df[["gdp", "inflation"]]| gdp | inflation | |
|---|---|---|
| 0 | 500 | 2.1 |
| 1 | 520 | 2.5 |
| 2 | 480 | 3.0 |
สร้างตัวแปรใหม่จากข้อมูลเดิม
ในงานเศรษฐศาสตร์ เรามักไม่ได้ใช้ข้อมูลดิบเพียงอย่างเดียว แต่จะสร้าง “ตัวแปรใหม่” เพื่อใช้ในการวิเคราะห์ เช่น อัตราการเติบโตของ GDP
เราสามารถใช้ Pandas เพื่อสร้างตัวแปรใหม่ได้ง่าย ๆ ดังนี้:
df["growth"] = df["gdp"].pct_change()
df| year | gdp | inflation | growth | |
|---|---|---|---|---|
| 0 | 2018 | 500 | 2.1 | NaN |
| 1 | 2019 | 520 | 2.5 | 0.040000 |
| 2 | 2020 | 480 | 3.0 | -0.076923 |
เมื่อข้อมูลถูกนำเข้าสู่ระบบในรูปแบบ DataFrame แล้ว ขั้นตอนต่อมาที่ถือเป็น “หัวใจ” ของงานเศรษฐมิติคือการสำรวจข้อมูล (EDA) เพื่อทำความเข้าใจพฤติกรรมแฝงของตัวแปร (Data Behavior) ก่อนที่จะเริ่มทำการประมาณค่าแบบจำลอง
Economics Insight: นักเศรษฐศาสตร์ที่เก่งจะไม่กระโดดเข้าหาการรัน Regression ทันที แต่จะใช้เวลาส่วนใหญ่ในการทำความเข้าใจ “ธรรมชาติของตัวเลข” เพื่อป้องกันปัญหาประเภท Garbage In, Garbage Out
นอกจากการใช้ .head() เพื่อดูส่วนหัวของข้อมูลแล้ว นักวิเคราะห์ควรสุ่มดูข้อมูลส่วนอื่นๆ ด้วย
# แสดง 5 แถวแรก
df.head()| year | gdp | inflation | growth | |
|---|---|---|---|---|
| 0 | 2018 | 500 | 2.1 | NaN |
| 1 | 2019 | 520 | 2.5 | 0.040000 |
| 2 | 2020 | 480 | 3.0 | -0.076923 |
# แสดง 5 แถวสุดท้าย เพื่อดูจุดสิ้นสุดของอนุกรมเวลาหรือข้อมูล
df.tail()| year | gdp | inflation | growth | |
|---|---|---|---|---|
| 0 | 2018 | 500 | 2.1 | NaN |
| 1 | 2019 | 520 | 2.5 | 0.040000 |
| 2 | 2020 | 480 | 3.0 | -0.076923 |
# สุ่มตัวอย่างข้อมูล 5 แถว เพื่อหาค่าที่อาจผิดปกติ (Outliers)
df.sample(5, replace=True)| year | gdp | inflation | growth | |
|---|---|---|---|---|
| 2 | 2020 | 480 | 3.0 | -0.076923 |
| 2 | 2020 | 480 | 3.0 | -0.076923 |
| 2 | 2020 | 480 | 3.0 | -0.076923 |
| 2 | 2020 | 480 | 3.0 | -0.076923 |
| 1 | 2019 | 520 | 2.5 | 0.040000 |
ทำไมต้องทำ?: ข้อมูลเศรษฐกิจมักมีการเรียงลำดับตามเวลา (Time Series) หรือตามพื้นที่ (Cross-sectional) การดูแค่ส่วนหัวอาจทำให้เราพลาดการเห็นความผิดปกติที่เกิดขึ้นในช่วงท้ายของชุดข้อมูล หรือความผิดปกติที่กระจายตัวอยู่ทั่วไป
การใช้ .info() ช่วยให้เราตรวจสอบ “ความพร้อม” ของข้อมูลในเชิงเทคนิค
df.info()<class 'pandas.DataFrame'>
RangeIndex: 3 entries, 0 to 2
Data columns (total 4 columns):
# Column Non-Null Count Dtype
--- ------ -------------- -----
0 year 3 non-null int64
1 gdp 3 non-null int64
2 inflation 3 non-null float64
3 growth 2 non-null float64
dtypes: float64(2), int64(2)
memory usage: 228.0 bytes
สิ่งที่นักเศรษฐศาสตร์ต้องพิจารณา:
Dtype (Data Type): ตัวแปรทางเศรษฐกิจบางตัวควรจะเป็นตัวเลข (float64) แต่อาจถูกจัดเก็บเป็นตัวอักษร (object) เนื่องจากมีสัญลักษณ์ปนมา (เช่น เครื่องหมาย comma ในค่าเงิน) ซึ่งต้องได้รับการแก้ไขก่อนคำนวณ
Non-Null Count: ตรวจสอบความสมบูรณ์ของข้อมูล หากพบว่ามี Null จำนวนมาก อาจส่งผลต่อความน่าเชื่อถือของผลการทดสอบทางสถิติ (Degrees of Freedom จะลดลง)
คำสั่ง .describe() คือจุดเริ่มต้นของการตั้งสมมติฐานทางเศรษฐศาสตร์
df.describe()| year | gdp | inflation | growth | |
|---|---|---|---|---|
| count | 3.0 | 3.0 | 3.000000 | 2.000000 |
| mean | 2019.0 | 500.0 | 2.533333 | -0.018462 |
| std | 1.0 | 20.0 | 0.450925 | 0.082677 |
| min | 2018.0 | 480.0 | 2.100000 | -0.076923 |
| 25% | 2018.5 | 490.0 | 2.300000 | -0.047692 |
| 50% | 2019.0 | 500.0 | 2.500000 | -0.018462 |
| 75% | 2019.5 | 510.0 | 2.750000 | 0.010769 |
| max | 2020.0 | 520.0 | 3.000000 | 0.040000 |
วิธีการตีความเชิงลึก:
Mean vs 50% (Median): หากค่าเฉลี่ยต่างจากค่ามัธยฐานมาก แสดงว่าข้อมูลมีการกระจายตัวที่เบ้ (Skewness) เช่น ข้อมูลรายได้ประชากร
Std (Standard Deviation): บอกถึงความผันผวน (Volatility) ของตัวแปร หากค่า Std สูงมากเมื่อเทียบกับ Mean แสดงว่าข้อมูลมีความแตกต่างกันสูง (Heterogeneity)
Min/Max: ช่วยตรวจสอบค่าที่ “เป็นไปไม่ได้” ในทางเศรษฐศาสตร์ เช่น อัตราเงินเฟ้อที่ติดลบมหาศาล หรืออายุของประชากรที่เป็นค่าลบ
ก่อนการสร้าง Multiple Regression เราควรดูความสัมพันธ์ระหว่างตัวแปรอิสระก่อนเสมอ
# ดูความสัมพันธ์ระหว่างตัวแปร
df.corr()| year | gdp | inflation | growth | |
|---|---|---|---|---|
| year | 1.000000 | -0.500000 | 0.997949 | -1.0 |
| gdp | -0.500000 | 1.000000 | -0.554416 | 1.0 |
| inflation | 0.997949 | -0.554416 | 1.000000 | -1.0 |
| growth | -1.000000 | 1.000000 | -1.000000 | 1.0 |
คำเตือน: หากตัวแปรอิสระสองตัวมีความสัมพันธ์กันสูงมาก (Correlation > 0.8) อาจนำไปสู่ปัญหา Multicollinearity ซึ่งจะทำให้ค่าสถิติ \(t\) ของแบบจำลองเศรษฐมิติไม่น่าเชื่อถือ
หากนักศึกษาคุ้นเคยกับการจัดการข้อมูลในภาษา R ด้วย tidyverse คุณจะพบว่า pandas มีชุดคำสั่งที่ทำงานได้เหมือนกันอย่างมีประสิทธิภาพ โดยเราจะใช้ข้อมูลตัวอย่างสินทรัพย์ 5 วันในการสาธิต:
import pandas as pd
# สร้างชุดข้อมูลจำลอง: ผลตอบแทนสินทรัพย์ (Asset Returns)
data = {
'Asset': ['Gold', 'Stock', 'Bitcoin', 'Gold', 'Stock'],
'Return': [0.5, -1.2, 5.4, 0.3, 2.1],
'Volume': [100, 500, 200, 150, 450]
}
df = pd.DataFrame(data)query() หรือ Boolean Indexing ในทางเศรษฐศาสตร์ เรามักต้องกรองข้อมูล เช่น เลือกเฉพาะช่วงวิกฤตเศรษฐกิจ หรือเลือกสินทรัพย์ที่มีผลตอบแทนเป็นบวก# เลือกเฉพาะแถวที่ Return > 0
positive_returns = df[df['Return'] > 0]
display(positive_returns)| Asset | Return | Volume | |
|---|---|---|---|
| 0 | Gold | 0.5 | 100 |
| 2 | Bitcoin | 5.4 | 200 |
| 3 | Gold | 0.3 | 150 |
| 4 | Stock | 2.1 | 450 |
# หรือใช้ .query() เพื่อความอ่านง่าย
positive_returns = df.query('Return > 0')
display(positive_returns)| Asset | Return | Volume | |
|---|---|---|---|
| 0 | Gold | 0.5 | 100 |
| 2 | Bitcoin | 5.4 | 200 |
| 3 | Gold | 0.3 | 150 |
| 4 | Stock | 2.1 | 450 |
assign() หรือ Direct Assignment ใช้ในการคำนวณตัวแปรใหม่ เช่น การคำนวณ Real Interest Rate จาก Nominal Rate และ Inflation# สร้างคอลัมน์ Turnover (Return * Volume)
df['Turnover'] = df['Return'] * df['Volume']
display(df)| Asset | Return | Volume | Turnover | |
|---|---|---|---|---|
| 0 | Gold | 0.5 | 100 | 50.0 |
| 1 | Stock | -1.2 | 500 | -600.0 |
| 2 | Bitcoin | 5.4 | 200 | 1080.0 |
| 3 | Gold | 0.3 | 150 | 45.0 |
| 4 | Stock | 2.1 | 450 | 945.0 |
## หรือ
df.assign(Turnover = lambda x: x.Return * x.Volume)
display(df)| Asset | Return | Volume | Turnover | |
|---|---|---|---|---|
| 0 | Gold | 0.5 | 100 | 50.0 |
| 1 | Stock | -1.2 | 500 | -600.0 |
| 2 | Bitcoin | 5.4 | 200 | 1080.0 |
| 3 | Gold | 0.3 | 150 | 45.0 |
| 4 | Stock | 2.1 | 450 | 945.0 |
[] หรือ filter() นักเศรษฐศาสตร์มักดึงเฉพาะตัวแปรอิสระที่สนใจออกมาจาก Dataset ขนาดใหญ่# เลือกเฉพาะคอลัมน์ Asset และ Return
df_subset = df[['Asset', 'Return']]
display(df_subset)| Asset | Return | |
|---|---|---|
| 0 | Gold | 0.5 |
| 1 | Stock | -1.2 |
| 2 | Bitcoin | 5.4 |
| 3 | Gold | 0.3 |
| 4 | Stock | 2.1 |
sort_values() ใช้ในการจัดลำดับ เช่น การหาจังหวัดที่มีรายได้สูงสุด (Top Income) หรือเรียงลำดับเหตุการณ์ตามเวลา# เรียงตาม Return จากมากไปน้อย (Descending)
df_sorted = df.sort_values(by='Return', ascending=False)
display(df_sorted)| Asset | Return | Volume | Turnover | |
|---|---|---|---|---|
| 2 | Bitcoin | 5.4 | 200 | 1080.0 |
| 4 | Stock | 2.1 | 450 | 945.0 |
| 0 | Gold | 0.5 | 100 | 50.0 |
| 3 | Gold | 0.3 | 150 | 45.0 |
| 1 | Stock | -1.2 | 500 | -600.0 |
groupby() + agg() หัวใจสำคัญของการทำ Descriptive Statistics รายกลุ่ม เช่น หาค่าเฉลี่ยรายได้แยกตามรายภาค# หาค่าเฉลี่ยผลตอบแทน (Return) แยกตามประเภทสินทรัพย์ (Asset)
summary_stats = df.groupby('Asset')['Return'].mean()
# หรือใช้ .agg() เพื่อหาหลายค่าพร้อมกัน
# summary_stats = df.groupby('Asset').agg({'Return': ['mean', 'std'], 'Volume': 'sum'})
display(summary_stats)Asset
Bitcoin 5.40
Gold 0.40
Stock 0.45
Name: Return, dtype: float64
เราจะผสมผสานทั้ง 5 Verbs เพื่อหาว่า “ในภูมิภาค Central และ North ใครมีอัตราการออม (Savings) สูงที่สุด 3 อันดับแรก”
import pandas as pd
import numpy as np
# 1. สร้างข้อมูลจำลอง (Synthetic Data)
data = {
'ID': range(1, 7),
'Region': ['Central', 'North', 'Central', 'South', 'North', 'Central'],
'Income': [50000, 32000, 45000, 38000, 29000, 60000],
'Spending': [42000, 28000, 35000, 39000, 25000, 48000]
}
df = pd.DataFrame(data)
# 2. ใช้ Mixed 5 Verbs ด้วย Method Chaining
# (Filter -> Mutate -> Select -> Arrange -> Summary)
report = (
df
# [Verb 1: Filter] เลือกเฉพาะภูมิภาค Central และ North
.query("Region in ['Central', 'North']")
# [Verb 2: Mutate] คำนวณเงินออม (Savings) และ อัตราการออม (Savings_Rate)
.assign(
Savings = lambda x: x['Income'] - x['Spending'],
Savings_Rate = lambda x: (x['Income'] - x['Spending']) / x['Income']
)
# [Verb 3: Select] เลือกเฉพาะคอลัมน์ที่ต้องการรายงาน
[['Region', 'Savings', 'Savings_Rate']]
# [Verb 4: Arrange] เรียงลำดับตามอัตราการออมจากมากไปน้อย
.sort_values(by='Savings_Rate', ascending=False)
# [Verb 5: Summary] ในที่นี้ขอแสดงผล 3 อันดับแรก (Top 3)
.head(3)
)
print("--- รายงานวิเคราะห์การออมรายบุคคล (Top 3) ---")
display(report)--- รายงานวิเคราะห์การออมรายบุคคล (Top 3) ---
| Region | Savings | Savings_Rate | |
|---|---|---|---|
| 2 | Central | 10000 | 0.222222 |
| 5 | Central | 12000 | 0.200000 |
| 0 | Central | 8000 | 0.160000 |
# แถมท้าย: [Verb 5: Summary แบบกลุ่ม] หาค่าเฉลี่ยรายภูมิภาค
regional_summary = (
df.groupby('Region')
.agg(
Avg_Income = ('Income', 'mean'),
Max_Savings = ('Income', lambda x: (df.loc[x.index, 'Income'] - df.loc[x.index, 'Spending']).max())
)
)
print("\n--- สรุปภาพรวมรายภูมิภาค ---")
display(regional_summary)
--- สรุปภาพรวมรายภูมิภาค ---
| Avg_Income | Max_Savings | |
|---|---|---|
| Region | ||
| Central | 51666.666667 | 12000 |
| North | 30500.000000 | 4000 |
| South | 38000.000000 | -1000 |
ในตัวอย่างต่อไป เราจะใช้ Method Chaining แบบเต็มรูปแบบเพื่อคำนวณหา “รายได้ที่แท้จริง” (Real Income) และคัดเลือกเฉพาะปีที่เศรษฐกิจมีประสิทธิภาพสูง
เราจะใช้ข้อมูลย้อนหลัง 5 ปีของประเทศสมมติแห่งหนึ่ง เพื่อดูว่าในปีใดที่รายได้เพิ่มขึ้นชนะเงินเฟ้อ
graph TD
A[(Raw Data)] --> B[Assign: คำนวณค่า Real/Productivity]
B --> C[Query: กรองเงินเฟ้อ CPI > 102]
C --> D[Select: เลือกเฉพาะคอลัมน์สำคัญ]
D --> E[Sort: เรียงตามประสิทธิภาพ]
E --> F[/Final Report/]
import pandas as pd
# 1. สร้างข้อมูลมหภาคจำลอง
data = {
'Year': [2019, 2020, 2021, 2022, 2023],
'Nominal_Income': [50000, 52000, 55000, 60000, 62000],
'CPI': [100, 102, 105, 112, 115], # ดัชนีราคาผู้บริโภค
'Labor_Hours': [2000, 2100, 2050, 2200, 2150]
}
df_macro = pd.DataFrame(data)
# 2. การประมวลผลข้อมูลด้วย 5 Verbs (Mixed Method Chaining)
# เป้าหมาย: คำนวณ Real_Income และ Productivity แล้วเลือกปีที่ Productivity > 25
analysis_result = (
df_macro
# [Verb 2: Mutate] คำนวณค่าทางเศรษฐศาสตร์ที่แท้จริง
.assign(
Real_Income = lambda x: (x['Nominal_Income'] / x['CPI']) * 100,
Productivity = lambda x: x['Nominal_Income'] / x['Labor_Hours']
)
# [Verb 1: Filter] เลือกเฉพาะปีที่ค่าครองชีพ (CPI) มากกว่า 102
.query("CPI > 102")
# [Verb 3: Select] เลือกเฉพาะตัวแปรเชิงเปรียบเทียบ
[['Year', 'Real_Income', 'Productivity']]
# [Verb 4: Arrange] เรียงจากปีที่มีประสิทธิภาพการผลิตสูงสุด
.sort_values(by='Productivity', ascending=False)
# [Verb 5: Summary] แสดงผลทั้งหมดที่ผ่านเงื่อนไข
)
print("--- ผลการวิเคราะห์รายได้ที่แท้จริงและประสิทธิภาพการผลิต ---")
display(analysis_result)--- ผลการวิเคราะห์รายได้ที่แท้จริงและประสิทธิภาพการผลิต ---
| Year | Real_Income | Productivity | |
|---|---|---|---|
| 4 | 2023 | 53913.043478 | 28.837209 |
| 3 | 2022 | 53571.428571 | 27.272727 |
| 2 | 2021 | 52380.952381 | 26.829268 |
ในโลกความเป็นจริง นักเศรษฐศาสตร์ไม่ได้สร้างข้อมูลด้วยมือ แต่ต้องดึงข้อมูลมาจากแหล่งต่างๆ เช่น ธนาคารแห่งประเทศไทย (BOT) หรือธนาคารโลก (World Bank) ซึ่ง Pandas มีฟังก์ชันที่รองรับการดึงข้อมูลทั้งจากไฟล์ในเครื่องและจาก URL โดยตรง:
วิธีนี้สะดวกที่สุดสำหรับนักศึกษา เพราะไม่ต้องดาวน์โหลดไฟล์ลงเครื่องก่อน เราจะลองดึงข้อมูล GDP ของประเทศไทย ย้อนหลังจากชุดข้อมูลของธนาคารโลก (ผ่าน GitHub)
import pandas as pd
from IPython.display import display
# ดึงข้อมูลจาก URL โดยตรง (ข้อมูล GDP รายประเทศทั่วโลก)
url = "https://raw.githubusercontent.com/datasets/gdp/master/data/gdp.csv"
df_world_gdp = pd.read_csv(url)
# กรองข้อมูล (Filtering) เฉพาะประเทศไทย
thailand_gdp = df_world_gdp[df_world_gdp['Country Name'] == 'Thailand']
# แสดงข้อมูล 5 แถวแรก
display(thailand_gdp.head())| Country Name | Country Code | Year | Value | |
|---|---|---|---|---|
| 12606 | Thailand | THA | 1960 | 2.760751e+09 |
| 12607 | Thailand | THA | 1961 | 3.034038e+09 |
| 12608 | Thailand | THA | 1962 | 3.308913e+09 |
| 12609 | Thailand | THA | 1963 | 3.540403e+09 |
| 12610 | Thailand | THA | 1964 | 3.889130e+09 |
ในไทย ข้อมูลเศรษฐกิจมักจัดเก็บในรูป Excel เราจะลองจำลองการสร้างไฟล์ Excel ที่มีหลาย Sheet แล้วฝึกการเลือกอ่านเฉพาะบาง Sheet
# จำลองการสร้างไฟล์ Excel เพื่อใช้เป็นกรณีศึกษาในห้องเรียน
with pd.ExcelWriter('economic_data.xlsx') as writer:
# Sheet 1: ข้อมูล GDP
thailand_gdp.to_excel(writer, sheet_name='GDP_Historical', index=False)
# Sheet 2: ข้อมูลจำลองอัตราดอกเบี้ย
pd.DataFrame({'Year': [2022, 2023], 'Rate': [1.25, 2.50]}).to_excel(writer, sheet_name='Interest_Rate', index=False)
# --- ขั้นตอนการเลือกอ่าน Sheet ที่ต้องการ ---
# หากไม่ระบุ sheet_name Pandas จะอ่านเฉพาะ Sheet แรกเสมอ
df_interest = pd.read_excel('economic_data.xlsx', sheet_name='Interest_Rate')
display(df_interest)| Year | Rate | |
|---|---|---|
| 0 | 2022 | 1.25 |
| 1 | 2023 | 2.50 |
ข้อมูลประเภทนี้คือการเปรียบเทียบตัวแปรระหว่างหน่วย (เช่น ประเทศ) ณ จุดเวลาใดเวลาหนึ่ง เพื่อความต่อเนื่อง เราจะสร้างชุดข้อมูลเศรษฐกิจของกลุ่มประเทศอาเซียนขึ้นมาเพื่อใช้ในตัวอย่างถัดไป:
import pandas as pd
from IPython.display import display
# สร้างชุดข้อมูลสำหรับใช้งานทั้งบท
data = {
'Year': [2022, 2022, 2023, 2023, 2022, 2022, 2023, 2023],
'Country': ['TH', 'VN', 'TH', 'VN', 'MY', 'SG', 'MY', 'SG'],
'GDP': [500, 400, 520, 430, 300, 600, 310, 610],
'Inflation': [1.5, 3.2, 2.1, 4.0, 2.5, 5.0, 2.8, 4.5]
}
df = pd.DataFrame(data)
# กรองข้อมูล (Filtering): เลือกเฉพาะแถวที่มี Inflation > 3
high_inflation = df[df['Inflation'] > 3]
display(high_inflation)| Year | Country | GDP | Inflation | |
|---|---|---|---|---|
| 1 | 2022 | VN | 400 | 3.2 |
| 3 | 2023 | VN | 430 | 4.0 |
| 5 | 2022 | SG | 600 | 5.0 |
| 7 | 2023 | SG | 610 | 4.5 |
เมื่อเรามีข้อมูลที่มีทั้งมิติหน่วย (Country) และเวลา (Year) เราสามารถใช้เทคนิคขั้นสูงเพื่อเตรียมข้อมูลสำหรับงานเศรษฐมิติได้ทันที:
# 1. การทำ De-meaning: ลบค่าเฉลี่ยรายกลุ่มเพื่อกำจัด Fixed Effects
df['GDP_mean'] = df.groupby('Country')['GDP'].transform('mean')
df['GDP_demeaned'] = df['GDP'] - df['GDP_mean']
# 2. การสร้างตัวแปร Lag (ปีก่อนหน้า): สำคัญมากในการวิเคราะห์ Time Lag
# ต้อง groupby ประเทศก่อนเพื่อไม่ให้ข้อมูลข้ามประเทศกัน
df['GDP_lag1'] = df.groupby('Country')['GDP'].shift(1)
display(df.head())| Year | Country | GDP | Inflation | GDP_mean | GDP_demeaned | GDP_lag1 | |
|---|---|---|---|---|---|---|---|
| 0 | 2022 | TH | 500 | 1.5 | 510.0 | -10.0 | NaN |
| 1 | 2022 | VN | 400 | 3.2 | 415.0 | -15.0 | NaN |
| 2 | 2023 | TH | 520 | 2.1 | 510.0 | 10.0 | 500.0 |
| 3 | 2023 | VN | 430 | 4.0 | 415.0 | 15.0 | 400.0 |
| 4 | 2022 | MY | 300 | 2.5 | 305.0 | -5.0 | NaN |
นี่คือจุดแข็งที่สุดของ Pandas สำหรับนักเศรษฐศาสตร์ (Economists) เพราะ Pandas รองรับการจัดการ Datetime Index ได้อย่างยอดเยี่ยม
# สร้างข้อมูลอนุกรมเวลาจำลอง
dates = pd.date_range(start='2023-01-01', periods=12, freq='ME')
prices = [100, 102, 105, 104, 108, 110, 115, 112, 118, 120, 125, 130]
ts_df = pd.DataFrame({'Price': prices}, index=dates)
# การคำนวณอัตราการเปลี่ยนแปลง (Inflation/Returns)
ts_df['Returns'] = ts_df['Price'].pct_change() * 100
# การทำ Resampling (เช่น จากข้อมูลรายเดือน เป็นรายไตรมาส)
quarterly_avg = ts_df.resample('ME').mean()ข้อมูลทางเศรษฐศาสตร์มักจะมีความผันผวน (Volatility) สูงในระยะสั้น การมองหาแนวโน้ม (Trend) ที่แท้จริงจึงทำได้ยาก เทคนิค Rolling Window หรือการคำนวณแบบหน้าต่างเลื่อน จะช่วยให้เราหา “ค่าเฉลี่ยเคลื่อนที่” (Moving Average) เพื่อดูทิศทางของข้อมูลได้ชัดเจนขึ้น
สมมติว่าเรามีข้อมูลราคาสินค้ารายวัน และต้องการดูค่าเฉลี่ยย้อนหลังทุกๆ 3 วัน เพื่อลดความผันผวนของราคา
# สร้างข้อมูลจำลองราคาที่มีความผันผวน
prices = pd.DataFrame({
'Price': [100, 102, 98, 105, 110, 108, 115]
})
# คำนวณค่าเฉลี่ยเคลื่อนที่ย้อนหลัง 3 ช่วงเวลา (3-day Moving Average)
prices['MA3'] = prices['Price'].rolling(window=3).mean()
display(prices)| Price | MA3 | |
|---|---|---|
| 0 | 100 | NaN |
| 1 | 102 | NaN |
| 2 | 98 | 100.000000 |
| 3 | 105 | 101.666667 |
| 4 | 110 | 104.333333 |
| 5 | 108 | 107.666667 |
| 6 | 115 | 111.000000 |
ในทางเศรษฐศาสตร์ เรามักจะทำ 12-month Moving Average กับข้อมูลเงินเฟ้อรายเดือน เพื่อตัดปัจจัยทางฤดูกาล (Seasonal factors) ออกไป
# ตัวอย่างการคำนวณค่าเฉลี่ยย้อนหลัง 12 เดือน (ในที่นี้จำลองข้อมูล 5 ช่วง)
# window=3 หมายถึงเอาค่าปัจจุบันรวมกับ 2 ค่าก่อนหน้ามาหาค่าเฉลี่ย
prices['Moving_Sum'] = prices['Price'].rolling(window=3).sum() # หาผลรวมย้อนหลัง
prices['Moving_Std'] = prices['Price'].rolling(window=3).std() # หาความผันผวนย้อนหลัง (Volatility)
display(prices)| Price | MA3 | Moving_Sum | Moving_Std | |
|---|---|---|---|---|
| 0 | 100 | NaN | NaN | NaN |
| 1 | 102 | NaN | NaN | NaN |
| 2 | 98 | 100.000000 | 300.0 | 2.000000 |
| 3 | 105 | 101.666667 | 305.0 | 3.511885 |
| 4 | 110 | 104.333333 | 313.0 | 6.027714 |
| 5 | 108 | 107.666667 | 323.0 | 2.516611 |
| 6 | 115 | 111.000000 | 333.0 | 3.605551 |
งานวิจัยทางเศรษฐศาสตร์ส่วนใหญ่มักต้องรวมข้อมูลจากหลายแหล่งเข้าด้วยกัน เช่น การนำข้อมูลดัชนีความเชื่อมั่นผู้บริโภคมาเชื่อมกับข้อมูลยอดขายรายเดือน โดยใช้ “วันที่” หรือ “ชื่อประเทศ” เป็นตัวเชื่อม (Key)
pd.merge() (เปรียบเสมือน VLOOKUP ใน Excel) สมมติว่าเรามีตาราง GDP และตารางอัตราการว่างงานแยกกัน เราต้องการรวมให้เป็นตารางเดียว# ตารางที่ 1: ข้อมูล GDP
df_gdp = pd.DataFrame({
'Country': ['Thailand', 'Vietnam', 'Malaysia'],
'GDP': [500, 400, 350]
})
# ตารางที่ 2: ข้อมูล Unemployment
df_unemp = pd.DataFrame({
'Country': ['Thailand', 'Vietnam', 'Singapore'],
'Unemployment': [1.2, 2.1, 3.5]
})
# รวมข้อมูลเข้าด้วยกันโดยใช้ Country เป็นตัวเชื่อม
# How='inner' คือเอาเฉพาะประเทศที่มีข้อมูลในทั้งสองตาราง
merged_df = pd.merge(df_gdp, df_unemp, on='Country', how='inner')
display(merged_df)| Country | GDP | Unemployment | |
|---|---|---|---|
| 0 | Thailand | 500 | 1.2 |
| 1 | Vietnam | 400 | 2.1 |
Inner Join: เอาเฉพาะแถวที่มี Key ตรงกันทั้งสองตาราง (เช่น สิงคโปร์และมาเลเซียจะหายไปเพราะข้อมูลไม่ครบ)
Left Join: เอาตารางซ้ายเป็นหลัก (เช่น เอาทุกประเทศในตาราง GDP แม้ไม่มีข้อมูลว่างงาน) ซึ่งนักเศรษฐศาสตร์นิยมใช้มากที่สุดเพื่อรักษาชุดข้อมูลหลักไว้
# ลองใช้ Left Join เพื่อรักษาข้อมูล Malaysia ไว้ (แม้จะไม่มีข้อมูล Unemployment)
left_merged = pd.merge(df_gdp, df_unemp, on='Country', how='left')
display(left_merged)| Country | GDP | Unemployment | |
|---|---|---|---|
| 0 | Thailand | 500 | 1.2 |
| 1 | Vietnam | 400 | 2.1 |
| 2 | Malaysia | 350 | NaN |
ข้อมูลพาเนลคือข้อมูลที่มีทั้งมิติของ “หน่วย” (Cross-section) และ “เวลา” (Time) รวมอยู่ด้วยกัน (เช่น ข้อมูล GDP ของ 10 ประเทศ ย้อนหลัง 20 ปี)
ใน Pandas เราจัดการข้อมูลประเภทนี้ด้วย MultiIndex หรือการจัดรูปแบบแบบ Long Format
# ตัวอย่างโครงสร้างข้อมูลพาเนล (Country-Year)
panel_data = {
'Year': [2022, 2022, 2023, 2023],
'Country': ['TH', 'VN', 'TH', 'VN'],
'GDP': [500, 400, 520, 430]
}
panel_df = pd.DataFrame(panel_data)
# ตั้งค่า Index เป็น 2 มิติ (Entity, Time)
panel_df = panel_df.set_index(['Country', 'Year'])
display(panel_df)| GDP | ||
|---|---|---|
| Country | Year | |
| TH | 2022 | 500 |
| VN | 2022 | 400 |
| TH | 2023 | 520 |
| VN | 2023 | 430 |
# การเข้าถึงข้อมูลเฉพาะกลุ่ม (เช่น ดูเฉพาะของ Thailand)
display(panel_df.loc['TH'])| GDP | |
|---|---|
| Year | |
| 2022 | 500 |
| 2023 | 520 |
ในงานเศรษฐศาสตร์จริง ข้อมูลมักจะไม่ครบถ้วน (Missing Data) เช่น บางประเทศอาจไม่มีการรายงานตัวเลข GDP ในบางปี หรือข้อมูลอัตราการว่างงานที่จัดเก็บรายไตรมาสแต่เราต้องการรายเดือน ในทางสถิติเราเรียกค่าว่างเหล่านี้ว่า NaN (Not a Number)
# สร้างข้อมูลที่มีค่าว่าง (None หรือ np.nan)
data_missing = {
'Year': [2020, 2021, 2022, 2023],
'GDP_Growth': [2.5, np.nan, 3.1, np.nan],
'Unemployment': [1.2, 1.5, np.nan, 1.8]
}
df_miss = pd.DataFrame(data_missing)
# ตรวจสอบจำนวนค่าว่างในแต่ละคอลัมน์
print(df_miss.isnull().sum())Year 0
GDP_Growth 2
Unemployment 1
dtype: int64
กลยุทธ์การจัดการข้อมูล (Strategies) นักเศรษฐศาสตร์มีวิธีรับมือกับ NaN หลักๆ 3 วิธี ขึ้นอยู่กับบริบทของข้อมูล:
# ลบแถวที่มีค่าว่างอย่างน้อย 1 คอลัมน์ออกไป
df_dropped = df_miss.dropna()
display(df_dropped)| Year | GDP_Growth | Unemployment | |
|---|---|---|---|
| 0 | 2020 | 2.5 | 1.2 |
* การเติมด้วยค่าสถิติ (Imputation) เช่น การเติมด้วยค่าเฉลี่ย (Mean) หรือมัธยฐาน (Median) ของกลุ่ม
# เติมค่าว่างใน GDP_Growth ด้วยค่าเฉลี่ยของปีที่มีข้อมูล
df_miss['GDP_filled'] = df_miss['GDP_Growth'].fillna(df_miss['GDP_Growth'].mean())* การเติมข้อมูลอนุกรมเวลา (Time Series Interpolation) สำหรับนักเศรษฐศาสตร์ วิธีนี้สำคัญมาก เช่น การใช้ค่าของปีก่อนหน้ามาแทนที่ (`Forward Fill`) หรือการลากเส้นแนวโน้มระหว่างจุด (`Interpolate`)
# Forward Fill (ffill): ใช้ค่าปีก่อนหน้ามาเติม (เช่น นโยบายปีก่อนยังส่งผลต่อเนื่อง)
df_miss['GDP_ffill'] = df_miss['GDP_Growth'].ffill()
# Linear Interpolation: ลากเส้นตรงเชื่อมระหว่างจุดข้อมูลที่มีอยู่
df_miss['Unemp_linear'] = df_miss['Unemployment'].interpolate()
display(df_miss)| Year | GDP_Growth | Unemployment | GDP_filled | GDP_ffill | Unemp_linear | |
|---|---|---|---|---|---|---|
| 0 | 2020 | 2.5 | 1.2 | 2.5 | 2.5 | 1.20 |
| 1 | 2021 | NaN | 1.5 | 2.8 | 2.5 | 1.50 |
| 2 | 2022 | 3.1 | NaN | 3.1 | 3.1 | 1.65 |
| 3 | 2023 | NaN | 1.8 | 2.8 | 3.1 | 1.80 |