دیتا سری

کتابخانه پانداز بر اساس نامپای نوشته شده است. در نامپای با ساختمان داده آرایه یک بُعدی آشنا شدیم. در پانداز نیز ساختمان داده‌ای به نام دیتاسری (Data Series) داریم که بسیار مشابه آرایه‌های یک بُعدی است. سری در واقع یک آرایه یک بُعدی به همراه نمایه (index) خاص است. در واقع در نامپای نمایه‌ها به طور پیش فرض عددی بودند (از 0 شروع می‌شدند تا n-1 که n طول آرایه بود) اما در پانداز در ساختمان داده سری نمایه‌ها می‌توانند موارد دلخواهی باشند، که در ادامه چند مورد را می‌بینیم. راحت ترین راه ایجاد سری، استفاده از لیست پایتون است.

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

import numpy as np
import pandas as pd
a = pd.Series([1, 4, 7, 5, 9])
b = pd.Series([1.1, 2.3, 5.6, 3.14])
c = pd.Series(['python', 'java', 'cpp', 'c'])
print(a)
print('----------------------')
print(b)
print('----------------------')
print(c)

خروجی کد:

0    1
1    4
2    7
3    5
4    9
dtype: int64
----------------------
0    1.10
1    2.30
2    5.60
3    3.14
dtype: float64
----------------------
0    python
1      java
2       cpp
3         c
dtype: object

مشاهده می‌کنیم که در سری، آرایه مقادیر در کنار خود آرایه اندیس (نمایه) را دارد. مثلاً در سری c (متغیر c که در آن نام 4 زبان را قرار داده‌ایم) کنار هر زبان یک اندیس متناظر با آن وجود دارد. به عبارت دیگر ستون سمت راست مقادیر ما هستند و ستون سمت چپ نمایه‌های ما هستند.

پانداز دستوری دارد که می‌توانیم آرایه مقادیر و آرایه نمایه‌ها را به صورت جدا نیز داشته باشیم به صورت زیر:

برای دسترسی به مقادیر:

a = pd.Series([-1, 5, 4, 8])
a.values

خروجی کد:

array([-1,  5,  4,  8], dtype=int64)

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

a.index

خروجی کد:

RangeIndex(start=0, stop=4, step=1)

می بینیم وقتی که فقط می‌خواهیم اندیس (نمایه) را چاپ کنیم (اگر نمایه‌های ما پیش فرض باشند یعنی همان عددی) خروجی ما یک RangeIndex است. که دقیقاً اشاره می‌کند شماره خانه‌ها از چی شروع و به چی ختم می‌شوند.

 

نکته: RangeIndex مشابه همان range پایتون است و به صورت پیش فرض نمایه‌های یک دیتاسری از این نوع استو مزیت RangeIndex سریع‌تر بودن آن است و برای نمایه‌های از نوع عدد صحیح به کار می‌رود.

 برای این که یک دیتاسری را به لیست تبدیل کنیم می‌توانیم از دستور .to_list() به صورت زیر استفاده کنیم.

a = pd.Series([12, 9, 4, -1, 10])
b = a.to_list()
print(b)
print(type(b))

خروجی کد:

[12, 9, 4, -1, 10]
<class 'list'>

همانطور که گفتیم پانداز از روی نامپای ساخته شده است. بنابراین تمام کار‌هایی که با یک آرایه نامپایی انجام می‌دادیم در سری‌ها نیز قابل انجام است. به چند نمونه از این موارد توجه کنید:

a = pd.Series([4, 12, 7, 9, 10])
print("Max a =", np.max(a))
print("Min a =", np.min(a))
print("Sum a =", np.sum(a))
print("Mean a =", np.mean(a))

خروجی کد:

Max a = 12
Min a = 4
Sum a = 42
Mean a = 8.4

 

نکته:توجه کنیم که توابعی که روی سری‌ها اعمال می‌کنیم برای values ها استفاده می‌شوند. در واقع وقتی می‌نویسیم np.max(a) این تابع ماکسیمم value ها را به ما میدهد و کاری به نمایه‌ها ندارد.

 همان‌طور که دیدیم در هنگام ساخت یک سری جدید، خود پانداز برای تمامی مقادیر، یک نمایه در نظر می‌گیرد. اما اگر بخواهیم می‌توانیم هر مقداری که مد نظرمان باشد را برای نمایه در نظر بگیریم. برای این منظور دو روش داریم. روش اول مقدار دهی نمایه‌ها در هنگام ایجاد دیتاسری است به صورت زیر:

s = pd.Series([19, 18, 20], index=['a', 'b', 'c'])
s

خروجی کد:

a    19
b    18
c    20
dtype: int64

می‌بینیم که نمایه‌های ما از اعداد 0 و 1و 2 به a و b و c تغییر کرده است.

روش دوم تغییر نمایه ها با استفاده از ویژگی index است که قبلاً آن را معرفی کرده بودیم. در واقع با استفاده از ویژگی index تنها نمایه‌ها را چاپ کردیم (دیدیم) اما می‌توانیم از همین ویژگی برای تغییر نمایه‌ها نیز استفاده کنیم. به مثال زیر توجه کنید:

s = pd.Series([19, 18, 20])
print(s)
print('---------------------')
s.index = ['a', 'b', 'c']
print(s)

خروجی کد:

0    19
1    18
2    20
dtype: int64
---------------------
a    19
b    18
c    20
dtype: int64

مشاهده می‌کنیم که در ابتدا سری با نمایه‌های عددی ساخته شد و سپس با استفاده از ویژگی index نمایه‌های آن را به حروف دلخواه تغییر دادیم.

نمایه سازی در سری

در این قسمت می‌خواهیم دسترسی به خانه‌های یک سری را توضیح دهیم.

فرض کنیم سری ما دارای نمایه‌های عددی باشد. به مثال زیر توجه کنید:

a = pd.Series([12, 4, 5, 10, 9])
print(a[0])
print(a[1])
print(a[2])
print(a[3])
print(a[4])

خروجی کد:

12
4
5
10
9

می‌بینیم که به راحتی همانند قبل توانستیم به خانه‌های یک سری با شماره خانه‌های آن دسترسی داشته باشیم.

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

nomarat = pd.Series([20, 18, 16, 15], index=['ali', 'reza', 'gholi', 'ahmad'])
print(nomarat)
print("--------------")
print(nomarat[0])

خروجی کد:

ali      20
reza     18
gholi    16
ahmad    15
dtype: int64
--------------
20

C:\Users\Ahmadreza\AppData\Local\Temp\ipykernel_22104\2428884271.py:4: FutureWarning: Series.__getitem__ treating keys as positions is deprecated. 
In a future version, integer keys will always be treated as labels (consistent with DataFrame behavior). To access a value by position, use `ser.iloc[pos]`
  print(nomarat[0])

می بینیم که در دیتاسری‌هایی که شامل نمایه‌های غیر عددی هستند می‌توانیم برای دسترسی به یک خانه از نمایه‌های عددی نیز استفاده کنیم. یعنی الان نمایه ali در جایگاه 0 است، نمایه reza در جایگاه 1 است، نمایه gholi در جایگاه 2 است و نمایه ahmad درجایگاه 3 است. اما در خروجی یک اخظاری را نیز مشاهده می‌کنیم. این اخطار می‌گوید که دسترسی به خانه‌های یک دیتاسری که نمایه‌های آن غیر عددی هستند با استفاده از نمایه‌های عددی به صورت بالا منقضی شده است. برای این منظور بهتر است که از دستور iloc به صورت زیر استفاده کنیم.

print(nomarat.iloc[0])

خروجی کد:

20

مشاهده می‌کنیم که برنامه بدون هیچ اخطاری اجرا شد.

اما یک سوال آیا می‌توانیم از نمایه‌های غیر عددی برای دسترسی به داده‌ها استفاده کنیم. جواب بله است به صورت زیر (روی همان دیتاسری nomarat مثال را بررسی می‌کنیم):

print(nomarat['ali'])

خروجی کد:

20

پس فقط کافیست تا نام نمایه را درون [ ] قرار دهیم.

علاوه بر روش بالا می‌توانیم با استفاده از دستور loc نیز به خانه‌ای دسترسی داشته باشیم. در واقع نام نمایه مورد نظر خود را درون این دستور قرار دهیم. به صورت زیر:

print(nomarat.loc['ali'])

خروجی کد:

20
توسعه دهندگان
احمدرضا آهنگریان