18. Pandas برای داده‌های پانلی#

علاوه بر آنچه در Anaconda موجود است، این سخنرانی به کتابخانه‌های زیر نیاز دارد:

!pip install --upgrade seaborn

Hide code cell output

Requirement already satisfied: seaborn in /home/runner/miniconda3/envs/quantecon/lib/python3.13/site-packages (0.13.2)
Requirement already satisfied: numpy!=1.24.0,>=1.20 in /home/runner/miniconda3/envs/quantecon/lib/python3.13/site-packages (from seaborn) (2.4.6)
Requirement already satisfied: pandas>=1.2 in /home/runner/miniconda3/envs/quantecon/lib/python3.13/site-packages (from seaborn) (3.0.3)
Requirement already satisfied: matplotlib!=3.6.1,>=3.4 in /home/runner/miniconda3/envs/quantecon/lib/python3.13/site-packages (from seaborn) (3.11.0)
Requirement already satisfied: contourpy>=1.0.1 in /home/runner/miniconda3/envs/quantecon/lib/python3.13/site-packages (from matplotlib!=3.6.1,>=3.4->seaborn) (1.3.3)
Requirement already satisfied: cycler>=0.10 in /home/runner/miniconda3/envs/quantecon/lib/python3.13/site-packages (from matplotlib!=3.6.1,>=3.4->seaborn) (0.12.1)
Requirement already satisfied: fonttools>=4.22.0 in /home/runner/miniconda3/envs/quantecon/lib/python3.13/site-packages (from matplotlib!=3.6.1,>=3.4->seaborn) (4.63.0)
Requirement already satisfied: kiwisolver>=1.3.1 in /home/runner/miniconda3/envs/quantecon/lib/python3.13/site-packages (from matplotlib!=3.6.1,>=3.4->seaborn) (1.4.9)
Requirement already satisfied: packaging>=20.0 in /home/runner/miniconda3/envs/quantecon/lib/python3.13/site-packages (from matplotlib!=3.6.1,>=3.4->seaborn) (26.0)
Requirement already satisfied: pillow>=9 in /home/runner/miniconda3/envs/quantecon/lib/python3.13/site-packages (from matplotlib!=3.6.1,>=3.4->seaborn) (12.3.0)
Requirement already satisfied: pyparsing>=3 in /home/runner/miniconda3/envs/quantecon/lib/python3.13/site-packages (from matplotlib!=3.6.1,>=3.4->seaborn) (3.2.5)
Requirement already satisfied: python-dateutil>=2.7 in /home/runner/miniconda3/envs/quantecon/lib/python3.13/site-packages (from matplotlib!=3.6.1,>=3.4->seaborn) (2.9.0.post0)
Requirement already satisfied: six>=1.5 in /home/runner/miniconda3/envs/quantecon/lib/python3.13/site-packages (from python-dateutil>=2.7->matplotlib!=3.6.1,>=3.4->seaborn) (1.17.0)

ما از import های زیر استفاده می‌کنیم.

import matplotlib.pyplot as plt
import seaborn as sns
sns.set_theme()

18.1. مروری کلی#

در سخنرانی پیشین درباره pandas، ما با مجموعه داده‌های ساده کار کردیم.

اقتصادسنجان اغلب نیاز به کار با مجموعه داده‌های پیچیده‌تر مانند پانل‌ها دارند.

وظایف رایج شامل موارد زیر است:

  • وارد کردن داده‌ها، تمیز کردن و تغییر شکل دادن آنها در چندین محور.

  • انتخاب یک سری زمانی یا مقطع عرضی از یک پانل.

  • گروه‌بندی و خلاصه کردن داده‌ها.

pandas (مشتق از ‘panel’ و ‘data’) شامل ابزارهای قدرتمند و آسان برای حل دقیقاً این نوع مشکلات است.

در ادامه، ما از یک مجموعه داده پانلی از حداقل دستمزدهای واقعی از OECD برای ایجاد موارد زیر استفاده خواهیم کرد:

  • آمار خلاصه در ابعاد مختلف داده‌های ما

  • یک سری زمانی از میانگین حداقل دستمزد کشورها در مجموعه داده

  • برآوردهای چگالی کرنل دستمزدها بر اساس قاره

ما با خواندن داده‌های پانلی فرمت طولانی خود از یک فایل CSV شروع می‌کنیم و DataFrame حاصل را با pivot_table تغییر شکل می‌دهیم تا یک MultiIndex بسازیم.

جزئیات اضافی با استفاده از تابع merge پانداز به DataFrame ما اضافه خواهد شد، و داده‌ها با تابع groupby خلاصه خواهند شد.

18.2. برش و تغییر شکل داده‌ها#

ما مجموعه داده‌ای از OECD از حداقل دستمزدهای واقعی در 32 کشور را می‌خوانیم و آن را به realwage اختصاص می‌دهیم.

مجموعه داده با لینک زیر قابل دسترسی است:

url1 = 'https://github.com/QuantEcon/data-lectures/raw/main/lectures/realwage.csv'
import pandas as pd

# Display 6 columns for viewing purposes
pd.set_option('display.max_columns', 6)

# Reduce decimal points to 2
pd.options.display.float_format = '{:,.2f}'.format

realwage = pd.read_csv(url1)

بیایید نگاهی به آنچه برای کار داریم بیندازیم

realwage.head()  # Show first 5 rows
Unnamed: 0 Time Country Series Pay period value
0 0 2006-01-01 Ireland In 2015 constant prices at 2015 USD PPPs Annual 17,132.44
1 1 2007-01-01 Ireland In 2015 constant prices at 2015 USD PPPs Annual 18,100.92
2 2 2008-01-01 Ireland In 2015 constant prices at 2015 USD PPPs Annual 17,747.41
3 3 2009-01-01 Ireland In 2015 constant prices at 2015 USD PPPs Annual 18,580.14
4 4 2010-01-01 Ireland In 2015 constant prices at 2015 USD PPPs Annual 18,755.83

داده‌ها در حال حاضر در فرمت طولانی هستند، که تجزیه و تحلیل آن زمانی که چندین بعد برای داده‌ها وجود دارد دشوار است.

ما از pivot_table برای ایجاد یک پانل با فرمت عریض، با یک MultiIndex برای مدیریت داده‌های چند بعدی بالاتر استفاده خواهیم کرد.

آرگومان‌های pivot_table باید داده‌ها (values)، index و ستون‌هایی که در dataframe نتیجه می‌خواهیم را مشخص کنند.

با ارسال یک لیست در columns، می‌توانیم یک MultiIndex در محور ستون خود ایجاد کنیم

realwage = realwage.pivot_table(values='value',
                                index='Time',
                                columns=['Country', 'Series', 'Pay period'])
realwage.head()
Country Australia ... United States
Series In 2015 constant prices at 2015 USD PPPs In 2015 constant prices at 2015 USD exchange rates ... In 2015 constant prices at 2015 USD PPPs In 2015 constant prices at 2015 USD exchange rates
Pay period Annual Hourly Annual ... Hourly Annual Hourly
Time
2006-01-01 20,410.65 10.33 23,826.64 ... 6.05 12,594.40 6.05
2007-01-01 21,087.57 10.67 24,616.84 ... 6.24 12,974.40 6.24
2008-01-01 20,718.24 10.48 24,185.70 ... 6.78 14,097.56 6.78
2009-01-01 20,984.77 10.62 24,496.84 ... 7.58 15,756.42 7.58
2010-01-01 20,879.33 10.57 24,373.76 ... 7.88 16,391.31 7.88

5 rows × 128 columns

برای فیلتر کردن آسان‌تر داده‌های سری زمانی خود، بعداً، ما index را به یک DateTimeIndex تبدیل خواهیم کرد

realwage.index = pd.to_datetime(realwage.index)
type(realwage.index)
pandas.DatetimeIndex

ستون‌ها شامل سطوح متعددی از نمایه‌سازی هستند، که به عنوان MultiIndex شناخته می‌شوند، با سطوحی که به صورت سلسله مراتبی مرتب شده‌اند (Country > Series > Pay period).

یک MultiIndex ساده‌ترین و انعطاف‌پذیرترین راه برای مدیریت داده‌های پانلی در pandas است

type(realwage.columns)
pandas.MultiIndex
realwage.columns.names
FrozenList(['Country', 'Series', 'Pay period'])

مانند قبل، می‌توانیم کشور (سطح بالای MultiIndex ما) را انتخاب کنیم

realwage['United States'].head()
Series In 2015 constant prices at 2015 USD PPPs In 2015 constant prices at 2015 USD exchange rates
Pay period Annual Hourly Annual Hourly
Time
2006-01-01 12,594.40 6.05 12,594.40 6.05
2007-01-01 12,974.40 6.24 12,974.40 6.24
2008-01-01 14,097.56 6.78 14,097.56 6.78
2009-01-01 15,756.42 7.58 15,756.42 7.58
2010-01-01 16,391.31 7.88 16,391.31 7.88

stacking و unstacking سطوح MultiIndex در سراسر این سخنرانی برای تغییر شکل dataframe ما به فرمتی که نیاز داریم استفاده خواهد شد.

.stack() پایین‌ترین سطح ستون MultiIndex را به index ردیف می‌چرخاند (.unstack() در جهت مخالف کار می‌کند - امتحان کنید)

realwage.stack().head()
Country Australia Belgium ... United Kingdom United States
Series In 2015 constant prices at 2015 USD PPPs In 2015 constant prices at 2015 USD exchange rates In 2015 constant prices at 2015 USD PPPs ... In 2015 constant prices at 2015 USD exchange rates In 2015 constant prices at 2015 USD PPPs In 2015 constant prices at 2015 USD exchange rates
Time Pay period
2006-01-01 Annual 20,410.65 23,826.64 21,042.28 ... 20,376.32 12,594.40 12,594.40
Hourly 10.33 12.06 10.09 ... 9.81 6.05 6.05
2007-01-01 Annual 21,087.57 24,616.84 21,310.05 ... 20,954.13 12,974.40 12,974.40
Hourly 10.67 12.46 10.22 ... 10.07 6.24 6.24
2008-01-01 Annual 20,718.24 24,185.70 21,416.96 ... 20,902.87 14,097.56 14,097.56

5 rows × 64 columns

همچنین می‌توانیم یک آرگومان برای انتخاب سطحی که می‌خواهیم stack کنیم ارسال کنیم

realwage.stack(level='Country').head()
Series In 2015 constant prices at 2015 USD PPPs In 2015 constant prices at 2015 USD exchange rates
Pay period Annual Hourly Annual Hourly
Time Country
2006-01-01 Australia 20,410.65 10.33 23,826.64 12.06
Belgium 21,042.28 10.09 20,228.74 9.70
Brazil 3,310.51 1.41 2,032.87 0.87
Canada 13,649.69 6.56 14,335.12 6.89
Chile 5,201.65 2.22 3,333.76 1.42

استفاده از یک DatetimeIndex انتخاب یک دوره زمانی خاص را آسان می‌کند.

انتخاب یک سال و stacking کردن دو سطح پایین‌تر MultiIndex یک مقطع عرضی از داده‌های پانلی ما ایجاد می‌کند

realwage.loc['2015'].stack(level=(1, 2)).transpose().head()
Time 2015-01-01
Series In 2015 constant prices at 2015 USD PPPs In 2015 constant prices at 2015 USD exchange rates
Pay period Annual Hourly Annual Hourly
Country
Australia 21,715.53 10.99 25,349.90 12.83
Belgium 21,588.12 10.35 20,753.48 9.95
Brazil 4,628.63 2.00 2,842.28 1.21
Canada 16,536.83 7.95 17,367.24 8.35
Chile 6,633.56 2.80 4,251.49 1.81

برای بقیه سخنرانی، ما با یک dataframe از حداقل دستمزدهای واقعی ساعتی در کشورها و زمان، اندازه‌گیری شده در دلار 2015 آمریکا کار خواهیم کرد.

برای ایجاد dataframe فیلتر شده خود (realwage_f)، می‌توانیم از متد xs برای انتخاب مقادیر در سطوح پایین‌تر در multiindex استفاده کنیم، در حالی که سطوح بالاتر (کشورها در این مورد) را حفظ می‌کنیم

realwage_f = realwage.xs(('Hourly', 'In 2015 constant prices at 2015 USD exchange rates'),
                         level=('Pay period', 'Series'), axis=1)
realwage_f.head()
Country Australia Belgium Brazil ... Turkey United Kingdom United States
Time
2006-01-01 12.06 9.70 0.87 ... 2.27 9.81 6.05
2007-01-01 12.46 9.82 0.92 ... 2.26 10.07 6.24
2008-01-01 12.24 9.87 0.96 ... 2.22 10.04 6.78
2009-01-01 12.40 10.21 1.03 ... 2.28 10.15 7.58
2010-01-01 12.34 10.05 1.08 ... 2.30 9.96 7.88

5 rows × 32 columns

18.3. ادغام Dataframe ها و پر کردن NaN ها#

مشابه پایگاه‌های داده رابطه‌ای مانند SQL، pandas متدهای داخلی برای ادغام مجموعه داده‌ها با هم دارد.

با استفاده از اطلاعات کشور از WorldData.info، ما قاره هر کشور را با تابع merge به realwage_f اضافه خواهیم کرد.

مجموعه داده با لینک زیر قابل دسترسی است:

url2 = 'https://github.com/QuantEcon/data-lectures/raw/main/lectures/countries.csv'
worlddata = pd.read_csv(url2, sep=';')
worlddata.head()
Country (en) Country (de) Country (local) ... Deathrate Life expectancy Url
0 Afghanistan Afghanistan Afganistan/Afqanestan ... 13.70 51.30 https://www.laenderdaten.info/Asien/Afghanista...
1 Egypt Ägypten Misr ... 4.70 72.70 https://www.laenderdaten.info/Afrika/Aegypten/...
2 Åland Islands Ålandinseln Åland ... 0.00 0.00 https://www.laenderdaten.info/Europa/Aland/ind...
3 Albania Albanien Shqipëria ... 6.70 78.30 https://www.laenderdaten.info/Europa/Albanien/...
4 Algeria Algerien Al-Jaza’ir/Algérie ... 4.30 76.80 https://www.laenderdaten.info/Afrika/Algerien/...

5 rows × 17 columns

ابتدا، ما فقط متغیرهای country و continent را از worlddata انتخاب می‌کنیم و ستون را به ‘Country’ تغییر نام می‌دهیم

worlddata = worlddata[['Country (en)', 'Continent']]
worlddata = worlddata.rename(columns={'Country (en)': 'Country'})
worlddata.head()
Country Continent
0 Afghanistan Asia
1 Egypt Africa
2 Åland Islands Europe
3 Albania Europe
4 Algeria Africa

می‌خواهیم dataframe جدید خود، worlddata، را با realwage_f ادغام کنیم.

تابع merge پانداز اجازه می‌دهد که dataframe ها با ردیف‌ها به هم متصل شوند.

dataframe های ما با استفاده از نام کشورها ادغام خواهند شد، که نیاز داریم از transpose realwage_f استفاده کنیم تا ردیف‌ها در هر دو dataframe با نام کشورها مطابقت داشته باشند

realwage_f.transpose().head()
Time 2006-01-01 2007-01-01 2008-01-01 ... 2014-01-01 2015-01-01 2016-01-01
Country
Australia 12.06 12.46 12.24 ... 12.67 12.83 12.98
Belgium 9.70 9.82 9.87 ... 10.01 9.95 9.76
Brazil 0.87 0.92 0.96 ... 1.21 1.21 1.24
Canada 6.89 6.96 7.24 ... 8.22 8.35 8.48
Chile 1.42 1.45 1.44 ... 1.76 1.81 1.91

5 rows × 11 columns

می‌توانیم از left، right، inner، یا outer join برای ادغام مجموعه داده‌های خود استفاده کنیم:

  • left join فقط کشورهای مجموعه داده سمت چپ را شامل می‌شود

  • right join فقط کشورهای مجموعه داده سمت راست را شامل می‌شود

  • outer join کشورهایی را که در مجموعه داده‌های سمت چپ و راست هستند شامل می‌شود

  • inner join فقط کشورهای مشترک بین مجموعه داده‌های سمت چپ و راست را شامل می‌شود

به طور پیش‌فرض، merge از یک inner join استفاده می‌کند.

در اینجا ما how='left' را ارسال خواهیم کرد تا همه کشورها در realwage_f را نگه داریم، اما کشورهایی در worlddata را که ورودی داده مربوطه در realwage_f ندارند دور بیندازیم.

این با سایه قرمز در نمودار زیر نشان داده شده است

_images/venn_diag.png

همچنین باید مشخص کنیم که نام کشور در هر dataframe کجا قرار دارد، که key خواهد بود که برای ادغام dataframe ها ‘on’ آن استفاده می‌شود.

dataframe ‘سمت چپ’ ما (realwage_f.transpose()) شامل کشورها در index است، بنابراین left_index=True را تنظیم می‌کنیم.

dataframe ‘سمت راست’ ما (worlddata) شامل کشورها در ستون ‘Country’ است، بنابراین right_on='Country' را تنظیم می‌کنیم

merged = pd.merge(realwage_f.transpose(), worlddata,
                  how='left', left_index=True, right_on='Country')
merged.head()
2006-01-01 00:00:00 2007-01-01 00:00:00 2008-01-01 00:00:00 ... 2016-01-01 00:00:00 Country Continent
17.00 12.06 12.46 12.24 ... 12.98 Australia Australia
23.00 9.70 9.82 9.87 ... 9.76 Belgium Europe
32.00 0.87 0.92 0.96 ... 1.24 Brazil South America
100.00 6.89 6.96 7.24 ... 8.48 Canada North America
38.00 1.42 1.45 1.44 ... 1.91 Chile South America

5 rows × 13 columns

کشورهایی که در realwage_f ظاهر شدند اما در worlddata نبودند NaN در ستون Continent خواهند داشت.

برای بررسی اینکه آیا این اتفاق افتاده است، می‌توانیم از .isnull() در ستون continent استفاده کنیم و dataframe ادغام شده را فیلتر کنیم

merged[merged['Continent'].isnull()]
2006-01-01 00:00:00 2007-01-01 00:00:00 2008-01-01 00:00:00 ... 2016-01-01 00:00:00 Country Continent
NaN 3.42 3.74 3.87 ... 5.28 Korea NaN
NaN 0.23 0.45 0.39 ... 0.55 Russian Federation NaN
NaN 1.50 1.64 1.71 ... 2.08 Slovak Republic NaN

3 rows × 13 columns

ما سه مقدار گمشده داریم!

یک گزینه برای مقابله با مقادیر NaN ایجاد یک dictionary حاوی این کشورها و قاره‌های مربوطه آنها است.

.map() کشورهای موجود در merged['Country'] را با قاره آنها از dictionary مطابقت می‌دهد.

توجه کنید که کشورهای موجود در dictionary ما با NaN نگاشت می‌شوند

missing_continents = {'Korea': 'Asia',
                      'Russian Federation': 'Europe',
                      'Slovak Republic': 'Europe'}

merged['Country'].map(missing_continents)
17.00        NaN
23.00        NaN
32.00        NaN
100.00       NaN
38.00        NaN
108.00       NaN
41.00        NaN
225.00       NaN
53.00        NaN
58.00        NaN
45.00        NaN
68.00        NaN
233.00       NaN
86.00        NaN
88.00        NaN
91.00        NaN
NaN         Asia
117.00       NaN
122.00       NaN
123.00       NaN
138.00       NaN
153.00       NaN
151.00       NaN
174.00       NaN
175.00       NaN
NaN       Europe
NaN       Europe
198.00       NaN
200.00       NaN
227.00       NaN
241.00       NaN
240.00       NaN
Name: Country, dtype: str

نمی‌خواهیم کل سری را با این نگاشت بازنویسی کنیم.

.fillna() فقط مقادیر NaN در merged['Continent'] را با نگاشت پر می‌کند، در حالی که سایر مقادیر در ستون بدون تغییر باقی می‌مانند

merged['Continent'] = merged['Continent'].fillna(merged['Country'].map(missing_continents))

# Check for whether continents were correctly mapped

merged[merged['Country'] == 'Korea']
2006-01-01 00:00:00 2007-01-01 00:00:00 2008-01-01 00:00:00 ... 2016-01-01 00:00:00 Country Continent
NaN 3.42 3.74 3.87 ... 5.28 Korea Asia

1 rows × 13 columns

همچنین قاره آمریکا را در یک قاره واحد ترکیب خواهیم کرد - این کار تجسم ما را بعداً زیباتر خواهد کرد.

برای انجام این کار، از .replace() استفاده خواهیم کرد و از طریق لیستی از مقادیر قاره‌ای که می‌خواهیم جایگزین کنیم حلقه می‌زنیم

replace = ['Central America', 'North America', 'South America']
merged['Continent'] = merged['Continent'].replace(to_replace=replace, value='America')

اکنون که همه داده‌هایی که می‌خواهیم در یک DataFrame واحد داریم، آن را به فرم پانلی با یک MultiIndex تغییر شکل خواهیم داد.

همچنین باید مطمئن شویم که index را با استفاده از .sort_index() مرتب کنیم تا بتوانیم بعداً به طور کارآمد dataframe خود را فیلتر کنیم.

به طور پیش‌فرض، سطوح از بالا به پایین مرتب خواهند شد

merged = merged.set_index(['Continent', 'Country']).sort_index()
merged.head()
2006-01-01 00:00:00 2007-01-01 00:00:00 2008-01-01 00:00:00 ... 2014-01-01 00:00:00 2015-01-01 00:00:00 2016-01-01 00:00:00
Continent Country
America Brazil 0.87 0.92 0.96 ... 1.21 1.21 1.24
Canada 6.89 6.96 7.24 ... 8.22 8.35 8.48
Chile 1.42 1.45 1.44 ... 1.76 1.81 1.91
Colombia 1.01 1.02 1.01 ... 1.13 1.13 1.12
Costa Rica NaN NaN NaN ... 2.41 2.56 2.63

5 rows × 11 columns

در حین ادغام، DatetimeIndex خود را از دست دادیم، زیرا ستون‌هایی را که در فرمت datetime نبودند ادغام کردیم

merged.columns
Index([2006-01-01 00:00:00, 2007-01-01 00:00:00, 2008-01-01 00:00:00,
       2009-01-01 00:00:00, 2010-01-01 00:00:00, 2011-01-01 00:00:00,
       2012-01-01 00:00:00, 2013-01-01 00:00:00, 2014-01-01 00:00:00,
       2015-01-01 00:00:00, 2016-01-01 00:00:00],
      dtype='object')

اکنون که ستون‌های ادغام شده را به عنوان index تنظیم کرده‌ایم، می‌توانیم یک DatetimeIndex با استفاده از .to_datetime() دوباره ایجاد کنیم

merged.columns = pd.to_datetime(merged.columns)
merged.columns = merged.columns.rename('Time')
merged.columns
DatetimeIndex(['2006-01-01', '2007-01-01', '2008-01-01', '2009-01-01',
               '2010-01-01', '2011-01-01', '2012-01-01', '2013-01-01',
               '2014-01-01', '2015-01-01', '2016-01-01'],
              dtype='datetime64[us]', name='Time', freq=None)

DatetimeIndex معمولاً در محور ردیف روان‌تر کار می‌کند، بنابراین ما پیش خواهیم رفت و merged را transpose خواهیم کرد

merged = merged.transpose()
merged.head()
Continent America ... Europe
Country Brazil Canada Chile ... Slovenia Spain United Kingdom
Time
2006-01-01 0.87 6.89 1.42 ... 3.92 3.99 9.81
2007-01-01 0.92 6.96 1.45 ... 3.88 4.10 10.07
2008-01-01 0.96 7.24 1.44 ... 3.96 4.14 10.04
2009-01-01 1.03 7.67 1.52 ... 4.08 4.32 10.15
2010-01-01 1.08 7.94 1.56 ... 4.81 4.30 9.96

5 rows × 32 columns

18.4. گروه‌بندی و خلاصه کردن داده‌ها#

گروه‌بندی و خلاصه کردن داده‌ها می‌تواند به ویژه برای درک مجموعه داده‌های پانلی بزرگ مفید باشد.

یک روش ساده برای خلاصه کردن داده‌ها فراخوانی یک متد تجمیعی در dataframe است، مانند .mean() یا .max().

به عنوان مثال، می‌توانیم میانگین حداقل دستمزد واقعی را برای هر کشور در دوره 2006 تا 2016 محاسبه کنیم (پیش‌فرض تجمیع بر روی ردیف‌ها است)

merged.mean().head(10)
Continent  Country      
America    Brazil          1.09
           Canada          7.82
           Chile           1.62
           Colombia        1.07
           Costa Rica      2.53
           Mexico          0.53
           United States   7.15
Asia       Israel          5.95
           Japan           6.18
           Korea           4.22
dtype: float64

با استفاده از این سری، می‌توانیم میانگین حداقل دستمزد واقعی را در طول دهه گذشته برای هر کشور در مجموعه داده خود رسم کنیم

merged.mean().sort_values(ascending=False).plot(kind='bar',
                                                title="Average real minimum wage 2006 - 2016")

# Set country labels
country_labels = merged.mean().sort_values(ascending=False).index.get_level_values('Country').tolist()
plt.xticks(range(0, len(country_labels)), country_labels)
plt.xlabel('Country')

plt.show()
_images/4e0382e2c220771d151e035d347bd19e2d687feadf27f52676e431ca14b2485f.png

ارسال axis=1 به .mean() بر روی ستون‌ها تجمیع خواهد کرد (میانگین حداقل دستمزد برای همه کشورها در طول زمان را می‌دهد)

merged.mean(axis=1).head()
Time
2006-01-01   4.69
2007-01-01   4.84
2008-01-01   4.90
2009-01-01   5.08
2010-01-01   5.11
dtype: float64

می‌توانیم این سری زمانی را به صورت یک نمودار خطی رسم کنیم

merged.mean(axis=1).plot()
plt.title('Average real minimum wage 2006 - 2016')
plt.ylabel('2015 USD')
plt.xlabel('Year')
plt.show()
_images/2706d53033f1feccdb29c292db197ebcb1a71a1e7897f7e6effc1a166f273589.png

همچنین می‌توانیم یک سطح از MultiIndex (در محور ستون) را برای تجمیع بر روی آن مشخص کنیم.

در مورد groupby، ما نیاز داریم از .T برای transpose کردن ستون‌ها به ردیف‌ها استفاده کنیم، زیرا pandas پشتیبانی از axis=1 را در متد groupby حذف کرده است.

merged.T.groupby(level='Continent').mean().head()
Time 2006-01-01 2007-01-01 2008-01-01 ... 2014-01-01 2015-01-01 2016-01-01
Continent
America 2.80 2.85 2.99 ... 3.22 3.26 3.30
Asia 4.29 4.44 4.45 ... 4.86 5.10 5.44
Australia 10.25 10.73 10.76 ... 11.25 11.52 11.73
Europe 4.80 4.94 4.99 ... 5.17 5.48 5.57

4 rows × 11 columns

می‌توانیم میانگین حداقل دستمزدها در هر قاره را به عنوان یک سری زمانی رسم کنیم

merged.T.groupby(level='Continent').mean().T.plot()
plt.title('Average real minimum wage')
plt.ylabel('2015 USD')
plt.xlabel('Year')
plt.show()
_images/e7a8dd9622fe8c1e50f65377c939226995b8ed1048e50a0ee9c4c93690cd2e8c.png

استرالیا را به عنوان یک قاره برای اهداف رسم حذف خواهیم کرد

merged = merged.drop('Australia', level='Continent', axis=1)
merged.T.groupby(level='Continent').mean().T.plot()
plt.title('Average real minimum wage')
plt.ylabel('2015 USD')
plt.xlabel('Year')
plt.show()
_images/7d88310209521a483dde7ac67ae2590ea28053f4c9788e70fe66aecb6cace335.png

.describe() برای بازیابی سریع تعدادی از آمار خلاصه رایج مفید است

merged.stack().describe()
Continent America Asia Europe
count 69.00 44.00 200.00
mean 3.19 4.70 5.15
std 3.02 1.56 3.82
min 0.52 2.22 0.23
25% 1.03 3.37 2.02
50% 1.44 5.48 3.54
75% 6.96 5.95 9.70
max 8.48 6.65 12.39

این یک روش ساده شده برای استفاده از groupby است.

استفاده از groupby به طور کلی از یک فرایند ‘تقسیم-اعمال-ترکیب’ پیروی می‌کند:

  • split: داده‌ها بر اساس یک یا چند کلید گروه‌بندی می‌شوند

  • apply: یک تابع به صورت مستقل روی هر گروه فراخوانی می‌شود

  • combine: نتایج فراخوانی‌های تابع در یک ساختار داده جدید ترکیب می‌شوند

متد groupby اولین مرحله از این فرایند را انجام می‌دهد، یک شیء DataFrameGroupBy جدید با داده‌های تقسیم شده به گروه‌ها ایجاد می‌کند.

بیایید merged را دوباره بر اساس قاره تقسیم کنیم، این بار با استفاده از تابع groupby، و شیء حاصل را grouped نامگذاری کنیم

grouped = merged.T.groupby(level='Continent')
grouped
<pandas.api.typing.DataFrameGroupBy object at 0x7faf58b29eb0>

فراخوانی یک متد تجمیعی روی شیء، تابع را به هر گروه اعمال می‌کند، که نتایج آن در یک ساختار داده جدید ترکیب می‌شوند.

به عنوان مثال، می‌توانیم تعداد کشورها در مجموعه داده خود را برای هر قاره با استفاده از .size() برگردانیم.

در این مورد، ساختار داده جدید ما یک Series است

grouped.size()
Continent
America     7
Asia        4
Europe     19
dtype: int64

با فراخوانی .get_group() برای برگرداندن فقط کشورها در یک گروه واحد، می‌توانیم یک برآورد چگالی کرنل از توزیع حداقل دستمزدهای واقعی در 2016 برای هر قاره ایجاد کنیم.

grouped.groups.keys() کلیدها را از شیء groupby برمی‌گرداند

continents = grouped.groups.keys()

for continent in continents:
    sns.kdeplot(grouped.get_group(continent).T.loc['2015'].unstack(), label=continent, fill=True)

plt.title('Real minimum wages in 2015')
plt.xlabel('US dollars')
plt.legend()
plt.show()
_images/0c527149a89ad718e4f663a835a874ad76ed1ab9e4448cba32efb5895ba295cb.png

18.5. نکات پایانی#

این سخنرانی مقدمه‌ای بر برخی از ویژگی‌های پیشرفته‌تر pandas، از جمله multiindex ها، ادغام، گروه‌بندی و رسم نمودار ارائه کرده است.

سایر ابزارهایی که ممکن است در تجزیه و تحلیل داده‌های پانلی مفید باشند شامل xarray می‌شوند، یک بسته پایتون که pandas را به ساختارهای داده N بعدی گسترش می‌دهد.

18.6. تمرین‌ها#

Exercise 18.1

در این تمرین‌ها، شما با یک مجموعه داده از نرخ‌های اشتغال در اروپا بر اساس سن و جنسیت از Eurostat کار خواهید کرد.

مجموعه داده با لینک زیر قابل دسترسی است:

url3 = 'https://github.com/QuantEcon/data-lectures/raw/main/lectures/employ.csv'

خواندن فایل CSV یک مجموعه داده پانلی در فرمت طولانی را برمی‌گرداند. از .pivot_table() برای ساخت یک dataframe با فرمت عریض با یک MultiIndex در ستون‌ها استفاده کنید.

با کاوش در dataframe و متغیرهای موجود در سطوح MultiIndex شروع کنید.

برنامه‌ای بنویسید که به سرعت همه مقادیر در MultiIndex را برمی‌گرداند.

Exercise 18.2

dataframe بالا را فیلتر کنید تا فقط اشتغال را به عنوان درصدی از ‘جمعیت فعال’ شامل شود.

یک boxplot گروه‌بندی شده با استفاده از seaborn از نرخ‌های اشتغال در 2015 بر اساس گروه سنی و جنسیت ایجاد کنید.