17. Pandas#

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

!pip install --upgrade wbgapi
!pip install --upgrade yfinance

Hide code cell output

Collecting wbgapi
  Downloading wbgapi-1.0.14-py3-none-any.whl.metadata (13 kB)
Requirement already satisfied: requests in /home/runner/miniconda3/envs/quantecon/lib/python3.13/site-packages (from wbgapi) (2.34.2)
Requirement already satisfied: PyYAML in /home/runner/miniconda3/envs/quantecon/lib/python3.13/site-packages (from wbgapi) (6.0.3)
Requirement already satisfied: tabulate in /home/runner/miniconda3/envs/quantecon/lib/python3.13/site-packages (from wbgapi) (0.10.0)
Requirement already satisfied: charset_normalizer<4,>=2 in /home/runner/miniconda3/envs/quantecon/lib/python3.13/site-packages (from requests->wbgapi) (3.4.7)
Requirement already satisfied: idna<4,>=2.5 in /home/runner/miniconda3/envs/quantecon/lib/python3.13/site-packages (from requests->wbgapi) (3.18)
Requirement already satisfied: urllib3<3,>=1.26 in /home/runner/miniconda3/envs/quantecon/lib/python3.13/site-packages (from requests->wbgapi) (2.7.0)
Requirement already satisfied: certifi>=2023.5.7 in /home/runner/miniconda3/envs/quantecon/lib/python3.13/site-packages (from requests->wbgapi) (2026.6.17)
Downloading wbgapi-1.0.14-py3-none-any.whl (36 kB)
Installing collected packages: wbgapi
Successfully installed wbgapi-1.0.14
Collecting yfinance
  Downloading yfinance-1.5.2-py2.py3-none-any.whl.metadata (6.2 kB)
Requirement already satisfied: pandas>=1.3.0 in /home/runner/miniconda3/envs/quantecon/lib/python3.13/site-packages (from yfinance) (3.0.3)
Requirement already satisfied: numpy>=1.16.5 in /home/runner/miniconda3/envs/quantecon/lib/python3.13/site-packages (from yfinance) (2.4.6)
Requirement already satisfied: requests>=2.31 in /home/runner/miniconda3/envs/quantecon/lib/python3.13/site-packages (from yfinance) (2.34.2)
Collecting multitasking>=0.0.7 (from yfinance)
  Downloading multitasking-0.0.13-py3-none-any.whl.metadata (16 kB)
Requirement already satisfied: platformdirs>=2.0.0 in /home/runner/miniconda3/envs/quantecon/lib/python3.13/site-packages (from yfinance) (4.9.4)
Collecting pytz>=2022.5 (from yfinance)
  Downloading pytz-2026.3.post1-py2.py3-none-any.whl.metadata (22 kB)
Collecting peewee>=3.16.2 (from yfinance)
  Downloading peewee-4.3.0-py3-none-any.whl.metadata (10 kB)
Requirement already satisfied: beautifulsoup4>=4.11.1 in /home/runner/miniconda3/envs/quantecon/lib/python3.13/site-packages (from yfinance) (4.15.0)
Collecting curl_cffi>=0.15 (from yfinance)
  Downloading curl_cffi-0.16.0-cp310-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl.metadata (17 kB)
Requirement already satisfied: protobuf>=3.19.0 in /home/runner/miniconda3/envs/quantecon/lib/python3.13/site-packages (from yfinance) (6.33.5)
Requirement already satisfied: websockets>=13.0 in /home/runner/miniconda3/envs/quantecon/lib/python3.13/site-packages (from yfinance) (16.0)
Requirement already satisfied: soupsieve>=1.6.1 in /home/runner/miniconda3/envs/quantecon/lib/python3.13/site-packages (from beautifulsoup4>=4.11.1->yfinance) (2.8.4)
Requirement already satisfied: typing-extensions>=4.0.0 in /home/runner/miniconda3/envs/quantecon/lib/python3.13/site-packages (from beautifulsoup4>=4.11.1->yfinance) (4.16.0)
Requirement already satisfied: cffi>=2.0.0 in /home/runner/miniconda3/envs/quantecon/lib/python3.13/site-packages (from curl_cffi>=0.15->yfinance) (2.1.0)
Requirement already satisfied: certifi>=2024.2.2 in /home/runner/miniconda3/envs/quantecon/lib/python3.13/site-packages (from curl_cffi>=0.15->yfinance) (2026.6.17)
Requirement already satisfied: pycparser in /home/runner/miniconda3/envs/quantecon/lib/python3.13/site-packages (from cffi>=2.0.0->curl_cffi>=0.15->yfinance) (3.0)
Requirement already satisfied: python-dateutil>=2.8.2 in /home/runner/miniconda3/envs/quantecon/lib/python3.13/site-packages (from pandas>=1.3.0->yfinance) (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.8.2->pandas>=1.3.0->yfinance) (1.17.0)
Requirement already satisfied: charset_normalizer<4,>=2 in /home/runner/miniconda3/envs/quantecon/lib/python3.13/site-packages (from requests>=2.31->yfinance) (3.4.7)
Requirement already satisfied: idna<4,>=2.5 in /home/runner/miniconda3/envs/quantecon/lib/python3.13/site-packages (from requests>=2.31->yfinance) (3.18)
Requirement already satisfied: urllib3<3,>=1.26 in /home/runner/miniconda3/envs/quantecon/lib/python3.13/site-packages (from requests>=2.31->yfinance) (2.7.0)
Downloading yfinance-1.5.2-py2.py3-none-any.whl (144 kB)
Downloading curl_cffi-0.16.0-cp310-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl (13.5 MB)
?25l   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 0.0/13.5 MB ? eta -:--:--
   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 13.5/13.5 MB 144.7 MB/s  0:00:00
?25hDownloading multitasking-0.0.13-py3-none-any.whl (16 kB)
Downloading peewee-4.3.0-py3-none-any.whl (179 kB)
Downloading pytz-2026.3.post1-py2.py3-none-any.whl (508 kB)
Installing collected packages: pytz, multitasking, peewee, curl_cffi, yfinance
?25l
   ━━━━━━━━━━━━━━━━╺━━━━━━━━━━━━━━━━━━━━━━━ 2/5 [peewee]
   ━━━━━━━━━━━━━━━━━━━━━━━━╺━━━━━━━━━━━━━━━ 3/5 [curl_cffi]
   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╺━━━━━━━ 4/5 [yfinance]
   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 5/5 [yfinance]
Successfully installed curl_cffi-0.16.0 multitasking-0.0.13 peewee-4.3.0 pytz-2026.3.post1 yfinance-1.5.2

17.1. مرور کلی#

Pandas یک بسته ابزارهای سریع و کارآمد برای تحلیل داده در Python است.

محبوبیت آن در سال‌های اخیر به طور همزمان با ظهور حوزه‌هایی مانند علم داده و یادگیری ماشین افزایش یافته است.

در اینجا مقایسه‌ای از محبوبیت در طول زمان در برابر Matlab و STATA از طریق Stack Overflow Trends آورده شده است

_images/pandas_vs_rest.png

همانطور که NumPy نوع داده آرایه پایه به اضافه عملیات اصلی آرایه را فراهم می‌کند، pandas

  1. ساختارهای بنیادین برای کار با داده را تعریف می‌کند و

  2. آنها را با متدهایی مجهز می‌کند که عملیات‌هایی مانند موارد زیر را تسهیل می‌کنند:

    • خواندن داده

    • تنظیم اندیس‌ها

    • کار با تاریخ‌ها و سری‌های زمانی

    • مرتب‌سازی، گروه‌بندی، مرتب‌سازی مجدد و به طور کلی تبدیل داده [1]

    • برخورد با مقادیر گمشده، و غیره

قابلیت‌های آماری پیچیده‌تر به بسته‌های دیگر مانند statsmodels و scikit-learn که بر روی pandas ساخته شده‌اند، واگذار می‌شود.

این درس مقدمه‌ای پایه به pandas ارائه خواهد داد.

در سراسر درس، فرض خواهیم کرد که import‌های زیر انجام شده است

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import requests

دو نوع داده مهم تعریف شده توسط pandas، Series و DataFrame هستند.

می‌توانید Series را به عنوان یک “ستون” از داده تصور کنید، مانند مجموعه‌ای از مشاهدات روی یک متغیر واحد.

DataFrame یک شیء دوبعدی برای ذخیره ستون‌های مرتبط از داده است.

17.2. Series#

بیایید با Series شروع کنیم.

با ایجاد یک سری از چهار مشاهده تصادفی شروع می‌کنیم

s = pd.Series(np.random.randn(4), name='daily returns')
s
0   -0.140920
1    0.094548
2    1.942897
3    1.116812
Name: daily returns, dtype: float64

در اینجا می‌توانید تصور کنید که اندیس‌های 0, 1, 2, 3 چهار شرکت فهرست شده را اندیس‌گذاری می‌کنند و مقادیر، بازده روزانه سهام آنها هستند.

Series در Pandas بر روی آرایه‌های NumPy ساخته شده‌اند و از بسیاری از عملیات مشابه پشتیبانی می‌کنند

s * 100
0    -14.092013
1      9.454799
2    194.289716
3    111.681197
Name: daily returns, dtype: float64
np.abs(s)
0    0.140920
1    0.094548
2    1.942897
3    1.116812
Name: daily returns, dtype: float64

اما Series بیش از آرایه‌های NumPy ارائه می‌دهند.

نه تنها آنها چند متد اضافی (با جهت‌گیری آماری) دارند

s.describe()
count    4.000000
mean     0.753334
std      0.962785
min     -0.140920
25%      0.035681
50%      0.605680
75%      1.323333
max      1.942897
Name: daily returns, dtype: float64

بلکه اندیس‌های آنها انعطاف‌پذیرتر هستند

s.index = ['AMZN', 'AAPL', 'MSFT', 'GOOG']
s
AMZN   -0.140920
AAPL    0.094548
MSFT    1.942897
GOOG    1.116812
Name: daily returns, dtype: float64

از این منظر، Series مانند دیکشنری‌های سریع و کارآمد Python هستند (با محدودیت اینکه تمام آیتم‌های دیکشنری از نوع یکسانی دارند — در این مورد، اعداد اعشاری).

در واقع، می‌توانید از بسیاری از نحو یکسان با دیکشنری‌های Python استفاده کنید

s['AMZN']
np.float64(-0.14092012791058728)
s['AMZN'] = 0
s
AMZN    0.000000
AAPL    0.094548
MSFT    1.942897
GOOG    1.116812
Name: daily returns, dtype: float64
'AAPL' in s
True

17.3. DataFrames#

در حالی که Series یک ستون واحد از داده است، DataFrame چندین ستون است، یکی برای هر متغیر.

در اصل، یک DataFrame در pandas مشابه یک صفحه گسترده Excel (بسیار بهینه شده) است.

بنابراین، یک ابزار قدرتمند برای نمایش و تحلیل داده‌هایی است که به طور طبیعی در سطرها و ستون‌ها سازماندهی شده‌اند، اغلب با اندیس‌های توصیفی برای سطرها و ستون‌های فردی.

بیایید به مثالی نگاه کنیم که داده را از فایل CSV pandas/data/test_pwt.csv می‌خواند، که از Penn World Tables گرفته شده است.

مجموعه داده شامل شاخص‌های زیر است

Variable Name

Description

POP

جمعیت (به هزار نفر)

XRAT

نرخ ارز به دلار آمریکا

tcgdp

کل تولید ناخالص داخلی تبدیل شده PPP (به میلیون دلار بین‌المللی)

cc

سهم مصرف از تولید ناخالص داخلی تبدیل شده PPP سرانه (٪)

cg

سهم مصرف دولت از تولید ناخالص داخلی تبدیل شده PPP سرانه (٪)

ما این را از یک URL با استفاده از تابع read_csv در pandas خواهیم خواند.

df = pd.read_csv('https://raw.githubusercontent.com/QuantEcon/lecture-python-programming/main/lectures/_static/lecture_specific/pandas/data/test_pwt.csv')
type(df)
pandas.DataFrame

در اینجا محتوای test_pwt.csv آمده است

df
country country isocode year POP XRAT tcgdp cc cg
0 Argentina ARG 2000 37335.653 0.999500 2.950722e+05 75.716805 5.578804
1 Australia AUS 2000 19053.186 1.724830 5.418047e+05 67.759026 6.720098
2 India IND 2000 1006300.297 44.941600 1.728144e+06 64.575551 14.072206
3 Israel ISR 2000 6114.570 4.077330 1.292539e+05 64.436451 10.266688
4 Malawi MWI 2000 11801.505 59.543808 5.026222e+03 74.707624 11.658954
5 South Africa ZAF 2000 45064.098 6.939830 2.272424e+05 72.718710 5.726546
6 United States USA 2000 282171.957 1.000000 9.898700e+06 72.347054 6.032454
7 Uruguay URY 2000 3219.793 12.099592 2.525596e+04 78.978740 5.108068

17.3.1. انتخاب داده بر اساس موقعیت#

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

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

df[2:5]
country country isocode year POP XRAT tcgdp cc cg
2 India IND 2000 1006300.297 44.941600 1.728144e+06 64.575551 14.072206
3 Israel ISR 2000 6114.570 4.077330 1.292539e+05 64.436451 10.266688
4 Malawi MWI 2000 11801.505 59.543808 5.026222e+03 74.707624 11.658954

برای انتخاب ستون‌ها، می‌توانیم لیستی حاوی نام ستون‌های مورد نظر را به صورت رشته ارسال کنیم

df[['country', 'tcgdp']]
country tcgdp
0 Argentina 2.950722e+05
1 Australia 5.418047e+05
2 India 1.728144e+06
3 Israel 1.292539e+05
4 Malawi 5.026222e+03
5 South Africa 2.272424e+05
6 United States 9.898700e+06
7 Uruguay 2.525596e+04

برای انتخاب هم سطرها و هم ستون‌ها با استفاده از اعداد صحیح، باید از ویژگی iloc با قالب .iloc[rows, columns] استفاده شود.

df.iloc[2:5, 0:4]
country country isocode year POP
2 India IND 2000 1006300.297
3 Israel ISR 2000 6114.570
4 Malawi MWI 2000 11801.505

برای انتخاب سطرها و ستون‌ها با استفاده از ترکیبی از اعداد صحیح و برچسب‌ها، می‌توان از ویژگی loc به روشی مشابه استفاده کرد

df.loc[df.index[2:5], ['country', 'tcgdp']]
country tcgdp
2 India 1.728144e+06
3 Israel 1.292539e+05
4 Malawi 5.026222e+03

17.3.2. انتخاب داده بر اساس شرایط#

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

این بخش روش‌های مختلف انجام این کار را نشان می‌دهد.

ساده‌ترین راه با عملگر [] است.

df[df.POP >= 20000]
country country isocode year POP XRAT tcgdp cc cg
0 Argentina ARG 2000 37335.653 0.99950 2.950722e+05 75.716805 5.578804
2 India IND 2000 1006300.297 44.94160 1.728144e+06 64.575551 14.072206
5 South Africa ZAF 2000 45064.098 6.93983 2.272424e+05 72.718710 5.726546
6 United States USA 2000 282171.957 1.00000 9.898700e+06 72.347054 6.032454

برای درک آنچه در اینجا اتفاق می‌افتد، توجه کنید که df.POP >= 20000 یک سری از مقادیر بولی را برمی‌گرداند.

df.POP >= 20000
0     True
1    False
2     True
3    False
4    False
5     True
6     True
7    False
Name: POP, dtype: bool

در این مورد، df[___] یک سری از مقادیر بولی را می‌گیرد و تنها سطرهایی با مقادیر True را برمی‌گرداند.

یک مثال دیگر بزنید،

df[(df.country.isin(['Argentina', 'India', 'South Africa'])) & (df.POP > 40000)]
country country isocode year POP XRAT tcgdp cc cg
2 India IND 2000 1006300.297 44.94160 1.728144e+06 64.575551 14.072206
5 South Africa ZAF 2000 45064.098 6.93983 2.272424e+05 72.718710 5.726546

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

# مورد بالا معادل است با 
df.query("POP >= 20000")
country country isocode year POP XRAT tcgdp cc cg
0 Argentina ARG 2000 37335.653 0.99950 2.950722e+05 75.716805 5.578804
2 India IND 2000 1006300.297 44.94160 1.728144e+06 64.575551 14.072206
5 South Africa ZAF 2000 45064.098 6.93983 2.272424e+05 72.718710 5.726546
6 United States USA 2000 282171.957 1.00000 9.898700e+06 72.347054 6.032454
df.query("country in ['Argentina', 'India', 'South Africa'] and POP > 40000")
country country isocode year POP XRAT tcgdp cc cg
2 India IND 2000 1006300.297 44.94160 1.728144e+06 64.575551 14.072206
5 South Africa ZAF 2000 45064.098 6.93983 2.272424e+05 72.718710 5.726546

همچنین می‌توانیم عملیات حسابی بین ستون‌های مختلف را مجاز کنیم.

df[(df.cc + df.cg >= 80) & (df.POP <= 20000)]
country country isocode year POP XRAT tcgdp cc cg
4 Malawi MWI 2000 11801.505 59.543808 5026.221784 74.707624 11.658954
7 Uruguay URY 2000 3219.793 12.099592 25255.961693 78.978740 5.108068
# مورد بالا معادل است با 
df.query("cc + cg >= 80 & POP <= 20000")
country country isocode year POP XRAT tcgdp cc cg
4 Malawi MWI 2000 11801.505 59.543808 5026.221784 74.707624 11.658954
7 Uruguay URY 2000 3219.793 12.099592 25255.961693 78.978740 5.108068

به عنوان مثال، می‌توانیم از شرط‌گذاری برای انتخاب کشوری با بیشترین سهم مصرف خانوار - تولید ناخالص داخلی cc استفاده کنیم.

df.loc[df.cc == max(df.cc)]
country country isocode year POP XRAT tcgdp cc cg
7 Uruguay URY 2000 3219.793 12.099592 25255.961693 78.97874 5.108068

وقتی فقط می‌خواهیم به ستون‌های خاصی از یک زیر دیتافریم انتخاب شده نگاه کنیم، می‌توانیم از شرایط بالا با دستور .loc[__ , __] استفاده کنیم.

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

df.loc[(df.cc + df.cg >= 80) & (df.POP <= 20000), ['country', 'year', 'POP']]
country year POP
4 Malawi 2000 11801.505
7 Uruguay 2000 3219.793

کاربرد: زیرمجموعه‌سازی دیتافریم

مجموعه داده‌های دنیای واقعی می‌توانند عظیم باشند.

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

فرض کنید که ما فقط به جمعیت (POP) و کل تولید ناخالص داخلی (tcgdp) علاقه‌مند هستیم.

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

df_subset = df[['country', 'POP', 'tcgdp']]
df_subset
country POP tcgdp
0 Argentina 37335.653 2.950722e+05
1 Australia 19053.186 5.418047e+05
2 India 1006300.297 1.728144e+06
3 Israel 6114.570 1.292539e+05
4 Malawi 11801.505 5.026222e+03
5 South Africa 45064.098 2.272424e+05
6 United States 282171.957 9.898700e+06
7 Uruguay 3219.793 2.525596e+04

سپس می‌توانیم مجموعه داده کوچکتر را برای تحلیل بیشتر ذخیره کنیم.

df_subset.to_csv('pwt_subset.csv', index=False)

17.3.3. متد Apply#

یکی دیگر از متدهای پرکاربرد Pandas، df.apply() است.

این یک تابع را به هر سطر/ستون اعمال می‌کند و یک سری را برمی‌گرداند.

این تابع می‌تواند برخی از توابع داخلی مانند تابع max، یک تابع lambda یا یک تابع تعریف شده توسط کاربر باشد.

در اینجا مثالی با استفاده از تابع max آورده شده است

df[['year', 'POP', 'XRAT', 'tcgdp', 'cc', 'cg']].apply(max)
year     2.000000e+03
POP      1.006300e+06
XRAT     5.954381e+01
tcgdp    9.898700e+06
cc       7.897874e+01
cg       1.407221e+01
dtype: float64

این خط کد تابع max را به تمام ستون‌های انتخاب شده اعمال می‌کند.

تابع lambda اغلب با متد df.apply() استفاده می‌شود

یک مثال بدیهی برگرداندن خودش برای هر سطر در دیتافریم است

df.apply(lambda row: row, axis=1)
country country isocode year POP XRAT tcgdp cc cg
0 Argentina ARG 2000 37335.653 0.999500 2.950722e+05 75.716805 5.578804
1 Australia AUS 2000 19053.186 1.724830 5.418047e+05 67.759026 6.720098
2 India IND 2000 1006300.297 44.941600 1.728144e+06 64.575551 14.072206
3 Israel ISR 2000 6114.570 4.077330 1.292539e+05 64.436451 10.266688
4 Malawi MWI 2000 11801.505 59.543808 5.026222e+03 74.707624 11.658954
5 South Africa ZAF 2000 45064.098 6.939830 2.272424e+05 72.718710 5.726546
6 United States USA 2000 282171.957 1.000000 9.898700e+06 72.347054 6.032454
7 Uruguay URY 2000 3219.793 12.099592 2.525596e+04 78.978740 5.108068

Note

برای متد .apply()

  • axis = 0 – اعمال تابع به هر ستون (متغیرها)

  • axis = 1 – اعمال تابع به هر سطر (مشاهدات)

  • axis = 0 پارامتر پیش‌فرض است

می‌توانیم آن را همراه با .loc[] برای انجام برخی انتخاب‌های پیشرفته‌تر استفاده کنیم.

complexCondition = df.apply(
    lambda row: row.POP > 40000 if row.country in ['Argentina', 'India', 'South Africa'] else row.POP < 20000, 
    axis=1), ['country', 'year', 'POP', 'XRAT', 'tcgdp']

df.apply() در اینجا یک سری از مقادیر بولی سطرهایی را که شرط مشخص شده در عبارت if-else را برآورده می‌کنند برمی‌گرداند.

علاوه بر این، زیرمجموعه‌ای از متغیرهای مورد علاقه را نیز تعریف می‌کند.

complexCondition
(0    False
 1     True
 2     True
 3     True
 4     True
 5     True
 6    False
 7     True
 dtype: bool,
 ['country', 'year', 'POP', 'XRAT', 'tcgdp'])

وقتی این شرط را به دیتافریم اعمال کنیم، نتیجه خواهد بود

df.loc[complexCondition]
country year POP XRAT tcgdp
1 Australia 2000 19053.186 1.724830 5.418047e+05
2 India 2000 1006300.297 44.941600 1.728144e+06
3 Israel 2000 6114.570 4.077330 1.292539e+05
4 Malawi 2000 11801.505 59.543808 5.026222e+03
5 South Africa 2000 45064.098 6.939830 2.272424e+05
7 Uruguay 2000 3219.793 12.099592 2.525596e+04

17.3.4. ایجاد تغییرات در DataFrames#

توانایی ایجاد تغییرات در دیتافریم‌ها برای تولید یک مجموعه داده تمیز برای تحلیل آینده مهم است.

1. می‌توانیم به راحتی از df.where() برای “نگه داشتن” سطرهایی که انتخاب کرده‌ایم استفاده کنیم و بقیه سطرها را با NaN جایگزین کنیم

df.where(df.POP >= 20000)
country country isocode year POP XRAT tcgdp cc cg
0 Argentina ARG 2000.0 37335.653 0.99950 2.950722e+05 75.716805 5.578804
1 NaN NaN NaN NaN NaN NaN NaN NaN
2 India IND 2000.0 1006300.297 44.94160 1.728144e+06 64.575551 14.072206
3 NaN NaN NaN NaN NaN NaN NaN NaN
4 NaN NaN NaN NaN NaN NaN NaN NaN
5 South Africa ZAF 2000.0 45064.098 6.93983 2.272424e+05 72.718710 5.726546
6 United States USA 2000.0 282171.957 1.00000 9.898700e+06 72.347054 6.032454
7 NaN NaN NaN NaN NaN NaN NaN NaN

2. به سادگی می‌توانیم از .loc[] برای مشخص کردن ستونی که می‌خواهیم تغییر دهیم استفاده کنیم و مقادیر را اختصاص دهیم

df.loc[df.cg == max(df.cg), 'cg'] = np.nan
df
country country isocode year POP XRAT tcgdp cc cg
0 Argentina ARG 2000 37335.653 0.999500 2.950722e+05 75.716805 5.578804
1 Australia AUS 2000 19053.186 1.724830 5.418047e+05 67.759026 6.720098
2 India IND 2000 1006300.297 44.941600 1.728144e+06 64.575551 NaN
3 Israel ISR 2000 6114.570 4.077330 1.292539e+05 64.436451 10.266688
4 Malawi MWI 2000 11801.505 59.543808 5.026222e+03 74.707624 11.658954
5 South Africa ZAF 2000 45064.098 6.939830 2.272424e+05 72.718710 5.726546
6 United States USA 2000 282171.957 1.000000 9.898700e+06 72.347054 6.032454
7 Uruguay URY 2000 3219.793 12.099592 2.525596e+04 78.978740 5.108068

3. می‌توانیم از متد .apply() برای تغییر سطرها/ستون‌ها به عنوان یک کل استفاده کنیم

def update_row(row):
    # تغییر POP
    row.POP = np.nan if row.POP<= 10000 else row.POP

    # تغییر XRAT
    row.XRAT = row.XRAT / 10
    return row

df.apply(update_row, axis=1)
country country isocode year POP XRAT tcgdp cc cg
0 Argentina ARG 2000 37335.653 0.099950 2.950722e+05 75.716805 5.578804
1 Australia AUS 2000 19053.186 0.172483 5.418047e+05 67.759026 6.720098
2 India IND 2000 1006300.297 4.494160 1.728144e+06 64.575551 NaN
3 Israel ISR 2000 NaN 0.407733 1.292539e+05 64.436451 10.266688
4 Malawi MWI 2000 11801.505 5.954381 5.026222e+03 74.707624 11.658954
5 South Africa ZAF 2000 45064.098 0.693983 2.272424e+05 72.718710 5.726546
6 United States USA 2000 282171.957 0.100000 9.898700e+06 72.347054 6.032454
7 Uruguay URY 2000 NaN 1.209959 2.525596e+04 78.978740 5.108068

4. می‌توانیم از متد .map() برای تغییر تمام ورودی‌های فردی در دیتافریم با هم استفاده کنیم.

# گرد کردن تمام اعداد اعشاری به 2 رقم اعشار
df.map(lambda x : round(x,2) if type(x)!=str else x)
country country isocode year POP XRAT tcgdp cc cg
0 Argentina ARG 2000 37335.65 1.00 295072.22 75.72 5.58
1 Australia AUS 2000 19053.19 1.72 541804.65 67.76 6.72
2 India IND 2000 1006300.30 44.94 1728144.37 64.58 NaN
3 Israel ISR 2000 6114.57 4.08 129253.89 64.44 10.27
4 Malawi MWI 2000 11801.50 59.54 5026.22 74.71 11.66
5 South Africa ZAF 2000 45064.10 6.94 227242.37 72.72 5.73
6 United States USA 2000 282171.96 1.00 9898700.00 72.35 6.03
7 Uruguay URY 2000 3219.79 12.10 25255.96 78.98 5.11

کاربرد: جایگزینی مقدار گمشده

جایگزینی مقادیر گمشده یک گام مهم در تبدیل داده است.

بیایید به طور تصادفی چند مقدار NaN وارد کنیم

for idx in list(zip([0, 3, 5, 6], [3, 4, 6, 2])):
    df.iloc[idx] = np.nan

df
country country isocode year POP XRAT tcgdp cc cg
0 Argentina ARG 2000.0 NaN 0.999500 2.950722e+05 75.716805 5.578804
1 Australia AUS 2000.0 19053.186 1.724830 5.418047e+05 67.759026 6.720098
2 India IND 2000.0 1006300.297 44.941600 1.728144e+06 64.575551 NaN
3 Israel ISR 2000.0 6114.570 NaN 1.292539e+05 64.436451 10.266688
4 Malawi MWI 2000.0 11801.505 59.543808 5.026222e+03 74.707624 11.658954
5 South Africa ZAF 2000.0 45064.098 6.939830 2.272424e+05 NaN 5.726546
6 United States USA NaN 282171.957 1.000000 9.898700e+06 72.347054 6.032454
7 Uruguay URY 2000.0 3219.793 12.099592 2.525596e+04 78.978740 5.108068

تابع zip() در اینجا جفت‌هایی از مقادیر دو لیست را ایجاد می‌کند (یعنی [0,3]، [3,4] …)

می‌توانیم دوباره از متد .map() برای جایگزینی تمام مقادیر گمشده با 0 استفاده کنیم

# جایگزینی تمام مقادیر NaN با 0
def replace_nan(x):
    if type(x)!=str:
        return  0 if np.isnan(x) else x
    else:
        return x

df.map(replace_nan)
country country isocode year POP XRAT tcgdp cc cg
0 Argentina ARG 2000.0 0.000 0.999500 2.950722e+05 75.716805 5.578804
1 Australia AUS 2000.0 19053.186 1.724830 5.418047e+05 67.759026 6.720098
2 India IND 2000.0 1006300.297 44.941600 1.728144e+06 64.575551 0.000000
3 Israel ISR 2000.0 6114.570 0.000000 1.292539e+05 64.436451 10.266688
4 Malawi MWI 2000.0 11801.505 59.543808 5.026222e+03 74.707624 11.658954
5 South Africa ZAF 2000.0 45064.098 6.939830 2.272424e+05 0.000000 5.726546
6 United States USA 0.0 282171.957 1.000000 9.898700e+06 72.347054 6.032454
7 Uruguay URY 2000.0 3219.793 12.099592 2.525596e+04 78.978740 5.108068

Pandas همچنین متدهای مناسبی برای جایگزینی مقادیر گمشده در اختیار ما قرار می‌دهد.

به عنوان مثال، جایگزینی تکی با استفاده از میانگین متغیرها به راحتی در pandas قابل انجام است

df = df.fillna(df.iloc[:,2:8].mean())
df
country country isocode year POP XRAT tcgdp cc cg
0 Argentina ARG 2000.0 1.962465e+05 0.999500 2.950722e+05 75.716805 5.578804
1 Australia AUS 2000.0 1.905319e+04 1.724830 5.418047e+05 67.759026 6.720098
2 India IND 2000.0 1.006300e+06 44.941600 1.728144e+06 64.575551 7.298802
3 Israel ISR 2000.0 6.114570e+03 18.178451 1.292539e+05 64.436451 10.266688
4 Malawi MWI 2000.0 1.180150e+04 59.543808 5.026222e+03 74.707624 11.658954
5 South Africa ZAF 2000.0 4.506410e+04 6.939830 2.272424e+05 71.217322 5.726546
6 United States USA 2000.0 2.821720e+05 1.000000 9.898700e+06 72.347054 6.032454
7 Uruguay URY 2000.0 3.219793e+03 12.099592 2.525596e+04 78.978740 5.108068

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

ابزارهای پیشرفته‌تر در python برای جایگزینی مقادیر گمشده نیز وجود دارد.

17.3.5. استانداردسازی و بصری‌سازی#

فرض کنیم که ما فقط به جمعیت (POP) و کل تولید ناخالص داخلی (tcgdp) علاقه‌مند هستیم.

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

df = df[['country', 'POP', 'tcgdp']]
df
country POP tcgdp
0 Argentina 1.962465e+05 2.950722e+05
1 Australia 1.905319e+04 5.418047e+05
2 India 1.006300e+06 1.728144e+06
3 Israel 6.114570e+03 1.292539e+05
4 Malawi 1.180150e+04 5.026222e+03
5 South Africa 4.506410e+04 2.272424e+05
6 United States 2.821720e+05 9.898700e+06
7 Uruguay 3.219793e+03 2.525596e+04

در اینجا اندیس 0, 1,..., 7 زائد است زیرا می‌توانیم از نام کشورها به عنوان اندیس استفاده کنیم.

برای انجام این کار، اندیس را به متغیر country در دیتافریم تنظیم می‌کنیم

df = df.set_index('country')
df
POP tcgdp
country
Argentina 1.962465e+05 2.950722e+05
Australia 1.905319e+04 5.418047e+05
India 1.006300e+06 1.728144e+06
Israel 6.114570e+03 1.292539e+05
Malawi 1.180150e+04 5.026222e+03
South Africa 4.506410e+04 2.272424e+05
United States 2.821720e+05 9.898700e+06
Uruguay 3.219793e+03 2.525596e+04

بیایید نام‌های بهتری به ستون‌ها بدهیم

df.columns = 'population', 'total GDP'
df
population total GDP
country
Argentina 1.962465e+05 2.950722e+05
Australia 1.905319e+04 5.418047e+05
India 1.006300e+06 1.728144e+06
Israel 6.114570e+03 1.292539e+05
Malawi 1.180150e+04 5.026222e+03
South Africa 4.506410e+04 2.272424e+05
United States 2.821720e+05 9.898700e+06
Uruguay 3.219793e+03 2.525596e+04

متغیر population به هزار نفر است، بیایید به واحدهای تکی برگردیم

df['population'] = df['population'] * 1e3
df
population total GDP
country
Argentina 1.962465e+08 2.950722e+05
Australia 1.905319e+07 5.418047e+05
India 1.006300e+09 1.728144e+06
Israel 6.114570e+06 1.292539e+05
Malawi 1.180150e+07 5.026222e+03
South Africa 4.506410e+07 2.272424e+05
United States 2.821720e+08 9.898700e+06
Uruguay 3.219793e+06 2.525596e+04

در مرحله بعد، قصد داریم ستونی که تولید ناخالص داخلی واقعی سرانه را نشان می‌دهد اضافه کنیم، و در ضمن در 1,000,000 ضرب می‌کنیم زیرا کل تولید ناخالص داخلی به میلیون است

df['GDP percap'] = df['total GDP'] * 1e6 / df['population']
df
population total GDP GDP percap
country
Argentina 1.962465e+08 2.950722e+05 1503.579625
Australia 1.905319e+07 5.418047e+05 28436.433261
India 1.006300e+09 1.728144e+06 1717.324719
Israel 6.114570e+06 1.292539e+05 21138.672749
Malawi 1.180150e+07 5.026222e+03 425.896679
South Africa 4.506410e+07 2.272424e+05 5042.647686
United States 2.821720e+08 9.898700e+06 35080.381854
Uruguay 3.219793e+06 2.525596e+04 7843.970620

یکی از ویژگی‌های خوب اشیاء DataFrame و Series در pandas این است که آنها متدهایی برای رسم نمودار و بصری‌سازی دارند که از طریق Matplotlib کار می‌کنند.

به عنوان مثال، می‌توانیم به راحتی یک نمودار میله‌ای از تولید ناخالص داخلی سرانه تولید کنیم

ax = df['GDP percap'].plot(kind='bar')
ax.set_xlabel('country', fontsize=12)
ax.set_ylabel('GDP per capita', fontsize=12)
plt.show()
_images/62b6086b846d95e8b501ec439d092e81dfb74e3d0861b6c63a2914025ae6d3c0.png

در حال حاضر دیتافریم به ترتیب الفبایی بر اساس کشورها مرتب شده است — بیایید آن را به تولید ناخالص داخلی سرانه تغییر دهیم

df = df.sort_values(by='GDP percap', ascending=False)
df
population total GDP GDP percap
country
United States 2.821720e+08 9.898700e+06 35080.381854
Australia 1.905319e+07 5.418047e+05 28436.433261
Israel 6.114570e+06 1.292539e+05 21138.672749
Uruguay 3.219793e+06 2.525596e+04 7843.970620
South Africa 4.506410e+07 2.272424e+05 5042.647686
India 1.006300e+09 1.728144e+06 1717.324719
Argentina 1.962465e+08 2.950722e+05 1503.579625
Malawi 1.180150e+07 5.026222e+03 425.896679

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

ax = df['GDP percap'].plot(kind='bar')
ax.set_xlabel('country', fontsize=12)
ax.set_ylabel('GDP per capita', fontsize=12)
plt.show()
_images/cf9894679094a5de5da34ca37e7e3f97b924154195e117f08c35f3b74113013c.png

17.4. منابع داده آنلاین#

Python پرس‌وجوی برنامه‌ای پایگاه‌های داده آنلاین را ساده می‌کند.

یک پایگاه داده مهم برای اقتصاددانان FRED است — یک مجموعه وسیع از داده‌های سری زمانی که توسط فدرال رزرو سنت لوئیس نگهداری می‌شود.

به عنوان مثال، فرض کنید که ما به نرخ بیکاری علاقه‌مند هستیم.

(برای دانلود داده به عنوان csv، روی Download در بالا سمت راست کلیک کرده و گزینه CSV (data) را انتخاب کنید).

از طرف دیگر، می‌توانیم به فایل CSV از داخل یک برنامه Python دسترسی پیدا کنیم.

این کار می‌تواند با انواع روش‌ها انجام شود.

ما با یک روش نسبتاً سطح پایین شروع می‌کنیم و سپس به pandas برمی‌گردیم.

17.4.1. دسترسی به داده با requests#

یک گزینه استفاده از requests است، یک کتابخانه استاندارد Python برای درخواست داده از طریق اینترنت.

برای شروع، کد زیر را روی کامپیوتر خود امتحان کنید

r = requests.get('https://fred.stlouisfed.org/graph/fredgraph.csv?bgcolor=%23e1e9f0&chart_type=line&drp=0&fo=open%20sans&graph_bgcolor=%23ffffff&height=450&mode=fred&recession_bars=on&txtcolor=%23444444&ts=12&tts=12&width=1318&nt=0&thu=0&trc=0&show_legend=yes&show_axis_titles=yes&show_tooltip=yes&id=UNRATE&scale=left&cosd=1948-01-01&coed=2024-06-01&line_color=%234572a7&link_values=false&line_style=solid&mark_type=none&mw=3&lw=2&ost=-99999&oet=99999&mma=0&fml=a&fq=Monthly&fam=avg&fgst=lin&fgsnd=2020-02-01&line_index=1&transformation=lin&vintage_date=2024-07-29&revision_date=2024-07-29&nd=1948-01-01')

اگر پیام خطایی نباشد، پس فراخوانی موفق بوده است.

اگر خطایی دریافت کردید، دو علت احتمالی وجود دارد

  1. شما به اینترنت متصل نیستید — امیدوارم که این مورد نباشد.

  2. دستگاه شما از طریق یک سرور پروکسی به اینترنت دسترسی پیدا می‌کند و Python از این موضوع آگاه نیست.

در حالت دوم، می‌توانید

  • به دستگاه دیگری تغییر دهید

  • مشکل پروکسی خود را با خواندن مستندات حل کنید

با فرض اینکه همه چیز کار می‌کند، اکنون می‌توانید از شیء source برگردانده شده توسط فراخوانی requests.get('https://research.stlouisfed.org/fred2/series/UNRATE/downloaddata/UNRATE.csv') استفاده کنید

url = 'https://fred.stlouisfed.org/graph/fredgraph.csv?bgcolor=%23e1e9f0&chart_type=line&drp=0&fo=open%20sans&graph_bgcolor=%23ffffff&height=450&mode=fred&recession_bars=on&txtcolor=%23444444&ts=12&tts=12&width=1318&nt=0&thu=0&trc=0&show_legend=yes&show_axis_titles=yes&show_tooltip=yes&id=UNRATE&scale=left&cosd=1948-01-01&coed=2024-06-01&line_color=%234572a7&link_values=false&line_style=solid&mark_type=none&mw=3&lw=2&ost=-99999&oet=99999&mma=0&fml=a&fq=Monthly&fam=avg&fgst=lin&fgsnd=2020-02-01&line_index=1&transformation=lin&vintage_date=2024-07-29&revision_date=2024-07-29&nd=1948-01-01'
source = requests.get(url).content.decode().split("\n")
source[0]
'observation_date,UNRATE'
source[1]
'1948-01-01,3.4'
source[2]
'1948-02-01,3.8'

اکنون می‌توانیم کد اضافی برای تجزیه این متن و ذخیره آن به عنوان یک آرایه بنویسیم.

اما این غیرضروری است — تابع read_csv در pandas می‌تواند این کار را برای ما انجام دهد.

از parse_dates=True استفاده می‌کنیم تا pandas ستون تاریخ‌های ما را تشخیص دهد و فیلتر کردن تاریخ ساده را امکان‌پذیر کند

data = pd.read_csv(url, index_col=0, parse_dates=True)

داده به یک DataFrame در pandas به نام data خوانده شده است که اکنون می‌توانیم به روش معمول با آن کار کنیم

type(data)
pandas.DataFrame
data.head()  # یک متد مفید برای نگاه سریع به دیتافریم
UNRATE
observation_date
1948-01-01 3.4
1948-02-01 3.8
1948-03-01 4.0
1948-04-01 3.9
1948-05-01 3.5
pd.set_option('display.precision', 1)
data.describe()  # خروجی شما ممکن است کمی متفاوت باشد
UNRATE
count 918.0
mean 5.7
std 1.7
min 2.5
25% 4.4
50% 5.5
75% 6.7
max 14.8

همچنین می‌توانیم نرخ بیکاری از 2006 تا 2012 را به شرح زیر رسم کنیم

ax = data['2006':'2012'].plot(title='US Unemployment Rate', legend=False)
ax.set_xlabel('year', fontsize=12)
ax.set_ylabel('%', fontsize=12)
plt.show()
_images/42bf16eef7bab69a0f7a5db2c9d4579ffd6b76bb915953608f5103240c64138c.png

توجه کنید که pandas گزینه‌های بسیار دیگری برای نوع فایل ارائه می‌دهد.

Pandas تنوع گسترده‌ای از متدهای سطح بالا دارد که می‌توانیم از آنها برای خواندن excel، json، parquet استفاده کنیم یا مستقیماً به یک سرور پایگاه داده وصل شویم.

17.4.2. استفاده از wbgapi و yfinance برای دسترسی به داده#

کتابخانه python wbgapi می‌تواند برای واکشی داده از پایگاه‌های داده متعددی که توسط بانک جهانی منتشر شده‌اند استفاده شود.

Note

می‌توانید اطلاعات مفیدی درباره بسته wbgapi در این پست وبلاگ بانک جهانی و همچنین این آموزش پیدا کنید

همچنین از yfinance برای واکشی داده از Yahoo finance در تمرین‌ها استفاده خواهیم کرد.

فعلاً بیایید یک مثال از دانلود و رسم نمودار داده را کار کنیم — این بار از بانک جهانی.

بانک جهانی داده را جمع‌آوری و سازماندهی می‌کند در مجموعه‌ای عظیم از شاخص‌ها.

به عنوان مثال، در اینجا برخی داده‌ها در مورد بدهی دولت به عنوان نسبتی از تولید ناخالص داخلی آورده شده است.

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

import wbgapi as wb
wb.series.info('GC.DOD.TOTL.GD.ZS')
---------------------------------------------------------------------------
APIError                                  Traceback (most recent call last)
Cell In[56], line 2
      1 import wbgapi as wb
----> 2 wb.series.info('GC.DOD.TOTL.GD.ZS')

File ~/miniconda3/envs/quantecon/lib/python3.13/site-packages/wbgapi/series.py:85, in info(id, q, topic, db)
     68 def info(id='all', q=None, topic=None, db=None):
     69     '''Print a user report of series. This can be time consuming
     70     for large databases like the WDI if 'all' series are requested.
     71 
   (...)     82         None
     83     '''
---> 85     return w.Featureset(list(id, q=q, topic=topic, db=db))

File ~/miniconda3/envs/quantecon/lib/python3.13/site-packages/wbgapi/__init__.py:190, in Featureset.__init__(self, items, columns)
    186 def __init__(self, items, columns=None):
    187     ''' can be initialized with any iterable
    188     '''
--> 190     self.items = list(items)
    191     self.columns = columns if columns else ['id', 'value']

File ~/miniconda3/envs/quantecon/lib/python3.13/site-packages/wbgapi/series.py:40, in list(id, q, topic, db)
     36         id = topics
     38 q,fullSearch = utils.qget(q)
---> 40 for row in w.source.features('series', w.queryParam(id, 'series', db=db), db=db):
     41     if utils.qmatch(q, row['value'], fullSearch):
     42         yield row

File ~/miniconda3/envs/quantecon/lib/python3.13/site-packages/wbgapi/__init__.py:322, in refetch(url, variables, **kwargs)
    320 try:
    321     for url2 in _refetch_url(url, variables[0], variables[1:], **kwargs):
--> 322         for row in fetch(url2, params, concepts, lang):
    323             yield row
    324 except URLError:

File ~/miniconda3/envs/quantecon/lib/python3.13/site-packages/wbgapi/__init__.py:281, in fetch(url, params, concepts, lang)
    278 while totalRecords is None or recordsRead < totalRecords:
    280     url_ = '{}/{}/{}?{}'.format(endpoint, lang, url, urllib.parse.urlencode(params_))
--> 281     (hdr,result) = _queryAPI(url_)
    283     if totalRecords is None:
    284         totalRecords = int(hdr['total'])

File ~/miniconda3/envs/quantecon/lib/python3.13/site-packages/wbgapi/__init__.py:530, in _queryAPI(url)
    528 response = requests.get(url, **params)
    529 if response.status_code != 200:
--> 530     raise APIError(url, response.reason, response.status_code)
    532 try:
    533     result = response.json()

APIError: APIError: [502] Bad Gateway (https://api.worldbank.org/v2/en/sources/2/series/GC.DOD.TOTL.GD.ZS?per_page=1000&page=1&format=json)
govt_debt = wb.data.DataFrame('GC.DOD.TOTL.GD.ZS', economy=['USA','AUS'], time=range(2005,2016))
govt_debt = govt_debt.T    # انتقال سال‌ها از ستون‌ها به سطرها برای رسم نمودار
govt_debt.plot(xlabel='year', ylabel='Government debt (% of GDP)');

17.5. تمرین‌ها#

Exercise 17.1

با این import‌ها:

import datetime as dt
import yfinance as yf

برنامه‌ای بنویسید تا درصد تغییر قیمت در سال 2021 را برای سهام زیر محاسبه کنید:

ticker_list = {'INTC': 'Intel',
               'MSFT': 'Microsoft',
               'IBM': 'IBM',
               'BHP': 'BHP',
               'TM': 'Toyota',
               'AAPL': 'Apple',
               'AMZN': 'Amazon',
               'C': 'Citigroup',
               'QCOM': 'Qualcomm',
               'KO': 'Coca-Cola',
               'GOOG': 'Google'}

در اینجا قسمت اول برنامه آورده شده است

def read_data(ticker_list,
          start=dt.datetime(2021, 1, 1),
          end=dt.datetime(2021, 12, 31)):
    """
    This function reads in closing price data from Yahoo
    for each tick in the ticker_list.
    """
    ticker = pd.DataFrame()

    for tick in ticker_list:
        stock = yf.Ticker(tick)
        prices = stock.history(start=start, end=end)

        # Change the index to date-only
        prices.index = pd.to_datetime(prices.index.date)
        
        closing_prices = prices['Close']
        ticker[tick] = closing_prices

    return ticker

ticker = read_data(ticker_list)

برنامه را تکمیل کنید تا نتیجه را به صورت نمودار میله‌ای مانند این رسم کنید:

_images/pandas_share_prices.png

Exercise 17.2

با استفاده از متد read_data معرفی شده در Exercise 17.1، برنامه‌ای بنویسید تا درصد تغییر سال به سال را برای شاخص‌های زیر به دست آورید:

indices_list = {'^GSPC': 'S&P 500',
               '^IXIC': 'NASDAQ',
               '^DJI': 'Dow Jones',
               '^N225': 'Nikkei'}

برنامه را تکمیل کنید تا آمار خلاصه را نشان دهد و نتیجه را به صورت نمودار سری زمانی مانند این رسم کنید:

_images/pandas_indices_pctchange.png