کتابخانه pandas در پایتون
پانداس، کتابخانهای است که کار با دادههای جدولی در پایتون را از یک کابوس حلقهمحور، به یک تجربهی روان و سریع تبدیل میکند. از Series و DataFrame تا
اولین بار که با یک فایل CSV صدهزار ردیفی روبرو شدم، تصمیم گرفتم با پایتون خالص پردازشش کنم: یک حلقهی for، چند دیکشنری، و کمی محاسبهی دستی. سی دقیقه بعد، برنامه هنوز در حال اجرا بود و حافظهی سیستم پر شده بود. همان روز، همکارم یک اسکریپت سهخطی پانداس به من نشان داد که همان کار را در کمتر از دو ثانیه انجام میداد. آن تجربه به من یاد داد که کتابخانه pandas در پایتون فقط یک ابزار جانبی نیست؛ ستون فقرات اکثر پروژههای تحلیل داده، هوش مصنوعی و مهندسی داده است. اگر میخواهید بدانید پانداس دقیقاً چه میکند، چرا اینقدر سریع است، و چطور در پروژههای واقعی از آن استفاده کنید، این مقاله همان مسیری را میرود که با تازهکارها طی میکنم.
پانداس چیست و چه دردی را درمان میکند؟
اگر تازه با پایتون آشنا شدهاید، اول آموزش پایتون از صفر را بخوانید. اما اگر پایتون را میشناسید، پانداس یک کتابخانهی متنباز است که برای کار با دادههای ساختاریافته (بهویژه جدولی) طراحی شده. کلمهی «pandas» از «panel data» گرفته شده — دادههای پنلی در آمار که به دادههای چندبعدی اشاره دارد.
پانداس دو ساختار دادهی اصلی دارد: Series (آرایهی یکبعدی با برچسب) و DataFrame (جدول دوبعدی). با همین دو ساختار، میتوانید کارهایی انجام دهید که در پایتون خالص، ساعتها وقت میگیرند:
- خواندن فایلهای CSV، Excel، JSON و پایگاه داده در یک خط.
- فیلتر کردن، مرتبسازی و گروهبندی داده با یک دستور.
- مدیریت دادههای گمشده بدون حلقههای پیچیده.
- ادغام چند جدول با منطق مشابه SQL.
- محاسبات سریع روی کل ستونها بهجای پیمایش خطبهخط.
نکتهای که در پروژههای واقعی به آن رسیدهام: پانداس اغلب بهعنوان «اکسل در پایتون» معرفی میشود، ولی این توصیف ناقص است. اکسل در حجم کوچک راحت است؛ پانداس دقیقاً وقتی میدرخشد که داده از حجم دستی عبور میکند — از چند هزار تا چند میلیون ردیف. اگر با فایلهای حجیم سر و کار دارید، کار با فایلها در پایتون پیشنیاز خوبی برای فهم بهتر مدیریت منابع در پانداس است.
پانداس، پایتون را از «زبان برنامهنویسی» به «زبان تحلیل داده» ارتقا میدهد؛ اگر داده دارید، پانداس ابزار کار شماست.
نصب پانداس و اولین تجربه
مثل هر کتابخانهی پایتونی، نصب پانداس در یک محیط مجازی انجام میشود. اگر با محیط مجازی آشنا نیستید، در آموزش پایتون از صفر توضیح دادهام:
python -m venv venv
source venv/bin/activate # در ویندوز: venv\Scripts\activate
pip install pandas openpyxl
pip freeze > requirements.txt
کتابخانهی openpyxl برای خواندن و نوشتن فایلهای Excel لازم است. اگر با فایلهای Excel کار میکنید، حتماً نصبش کنید. همچنین اگر با دادههای عددی سنگین کار میکنید، numpy هم بهطور خودکار نصب میشود چون پانداس بر پایهی آن ساخته شده.
اولین تجربهی پانداس، ساخت یک DataFrame ساده است:
import pandas as pd
df = pd.DataFrame({
"name": ["Ali", "Sara", "Reza"],
"age": [30, 25, 35],
"city": ["Tehran", "Isfahan", "Shiraz"],
})
print(df)
خروجی، یک جدول خوانا با ایندکس خودکار است:
name age city
0 Ali 30 Tehran
1 Sara 25 Isfahan
2 Reza 35 Shiraz
همین سه خط، نشاندهندهی قدرت پانداس است: بدون حلقه، بدون تابع کمکی، یک جدول تمیز در اختیار دارید. از این لحظه، میتوانید داده را فیلتر کنید، مرتب کنید یا روی آن محاسبه انجام دهید.
Series: اولین ساختار داده
Series در پانداس، یک آرایهی یکبعدی با برچسب است. مثل یک ستون از جدول، یا یک دیکشنری مرتب:
import pandas as pd
prices = pd.Series([1200, 800, 950], index=["apple", "banana", "cherry"])
print(prices["apple"]) # 1200
print(prices.mean()) # 983.33
print(prices[prices > 900])
سه ویژگی Series که در پروژههای واقعی حیاتی است:
- ایندکس برچسبی: برخلاف لیست که فقط اندیس عددی دارد، Series میتواند با هر برچسبی ایندکس شود — رشته، تاریخ، عدد. همین ویژگی، کار با دادههای واقعی را بسیار راحتتر میکند.
- عملیات برداری: وقتی
prices > 900مینویسید، پانداس بهجای حلقه، کل آرایه را در یک عملیات مقایسه میکند. این کار، اساس سرعت پانداس است. - مدیریت خودکار مقادیر گمشده: Series میتواند مقادیر
NaNداشته باشد و در محاسبات، آنها را بهطور هوشمند نادیده بگیرد.
یک نکتهی ظریف در پروژههای واقعی: عملیات روی Series، برخلاف لیستهای پایتون، معمولاً بین عناصر همایندکس عملیات انجام میدهد — نه بهترتیب. اگر دو Series با ایندکس متفاوت را جمع کنید، پانداس عناصر همنام را با هم جمع میکند و بقیه را NaN میگذارد. این رفتار، هم قدرت است و هم میتواند منبع باگ شود اگر به آن توجه نکنید.
a = pd.Series([1, 2, 3], index=["x", "y", "z"])
b = pd.Series([10, 20, 30], index=["y", "z", "w"])
print(a + b)
# x NaN
# y 22.0
# z 33.0
# w NaN
اگر با آرایههای PHP آشنا هستید، کار با آرایهها در PHP نمونهای از پردازش دستی دادههاست — فقط برای اینکه تفاوت این رویکرد با قدرت Series را بهتر حس کنید.
DataFrame: قلب پانداس
DataFrame، ساختار اصلی پانداس است. یک جدول دوبعدی با ایندکس سطری و برچسب ستونی:
df = pd.DataFrame({
"order_id": [1, 2, 3, 4],
"customer": ["Ali", "Sara", "Reza", "Ali"],
"product": ["Book", "Pen", "Notebook", "Book"],
"quantity": [2, 5, 1, 3],
"price": [120, 20, 80, 120],
})
print(df)
DataFrame مجموعهای از Series است که یک ایندکس مشترک دارند. همین ویژگی، عملیات روی کل ستون را ممکن میکند:
df["total"] = df["quantity"] * df["price"]
print(df["total"].sum())
در پانداس، ستونها با df["column"] و سطرها با df.loc[...] یا df.iloc[...] قابل دسترسی هستند. تفاوت این دو را جدی بگیرید چون در پروژههای واقعی، اشتباه گرفتنشان منبع باگ است:
| عملگر | نوع دسترسی | مثال |
|---|---|---|
df.loc | بر اساس برچسب | df.loc[0, "name"] |
df.iloc | بر اساس موقعیت عددی | df.iloc[0, 1] |
df.at | دسترسی سریع به یک مقدار خاص برچسبی | df.at[0, "name"] |
df.iat | دسترسی سریع به یک مقدار خاص موقعیتی | df.iat[0, 1] |
یک توصیهی مهم از تجربه: از df.at و df.iat برای دسترسی به یک سلول خاص استفاده کنید. سرعتشان چند برابر df.loc است و برای حلقههای پردازش داده، تفاوت محسوسی میسازند.
خواندن داده از CSV، Excel و JSON
بیشترین کاربرد پانداس در پروژههای واقعی، خواندن داده از فایل است. تابع read_csv قدرتمندترین ابزار پانداس در این زمینه است:
df = pd.read_csv("sales.csv", encoding="utf-8")
print(df.head())
نکتهی مهم برای دادههای فارسی، همان درس همیشگی است: همیشه encoding="utf-8" را صریح مشخص کنید. اگر فایل فارسی با انکودینگ دیگری ذخیره شده، ممکن است به خطای UnicodeDecodeError بربخورید — همان خطایی که در رفع خطای UnicodeDecodeError در پایتون راههای تشخیص و رفعش را آوردهام.
پارامترهای مهم read_csv
در پروژههای واقعی، فایلهای CSV همیشه تمیز نیستند. پارامترهای زیر را زیاد استفاده میکنم:
df = pd.read_csv(
"sales.csv",
encoding="utf-8",
sep=",",
header=0,
usecols=["order_id", "customer", "total"],
dtype={"order_id": "int32", "total": "float32"},
parse_dates=["order_date"],
na_values=["", "NA", "?"]
)
usecols: فقط ستونهایی که لازم دارید بخوانید. برای فایلهای حجیم، این پارامتر مصرف حافظه را چند برابر کاهش میدهد.dtype: نوع دادهی هر ستون را از ابتدا تعیین کنید. مخصوصاً برای ستونهای عددی، تفاوتint64وint32در حجم بزرگ، محسوس است.parse_dates: تاریخها را در همان مرحلهی خواندن، تبدیل به نوعdatetimeکنید. این کار جلوتر، تحلیل سری زمانی را ساده میکند.na_values: مقادیری که پانداس باید بهعنوان «گمشده» در نظر بگیرد. پیشفرض پانداس فقط چند الگو را میشناسد؛ اگر دادهی شما از"?"استفاده میکند، بدون این پارامتر، آن را بهعنوان رشته میخواند.
خواندن فایلهای دیگر
# Excel
df = pd.read_excel("sales.xlsx", sheet_name="Q1")
# JSON
df = pd.read_json("data.json")
# دیتابیس SQL
from sqlalchemy import create_engine
engine = create_engine("mysql+pymysql://user:pass@host/db")
df = pd.read_sql("SELECT * FROM orders", engine)
اگر با اتصال پایتون به MySQL آشنا نیستید، اتصال پایتون به MySQL مسیر کامل را نشان میدهد. برای دادهای که از یک API میآید، وب اسکرپینگ با پایتون نمونهی طبیعیای است که خروجیاش را به پانداس میریزید.
کاوش اولیهی داده
قبل از هر تحلیلی، باید داده را بشناسید. این مرحله، در پروژههای واقعی حیاتی است — چون نیمی از باگهای تحلیل، ناشی از نشناختن ساختار داده است. شش متدی که هر روز استفاده میکنم:
df.head(10) # ده سطر اول
df.tail(10) # ده سطر آخر
df.info() # انواع داده، مقادیر غیرگمشده، مصرف حافظه
df.describe() # آمار توصیفی ستونهای عددی
df.shape # (تعداد سطر، تعداد ستون)
df.columns.tolist() # فهرست ستونها
خروجی df.info() در پروژههای واقعی، اولین جایی است که به آن نگاه میکنم. سه چیز مهم در آن میبینم:
- نوع داده هر ستون: اگر ستون عددی بهعنوان
object(رشته) نمایش داده شود، حتماً چیزی غیرعددی در آن هست. مثلاً جداکنندهی هزارگان، یا فاصلهی اضافه. - تعداد مقادیر غیرگمشده: اگر ستونی هزار سطر دارد ولی فقط ۹۵۰ مقدار غیرگمشده، یعنی ۵۰ مقدار گمشده دارد — این را باید در تحلیل بهحساب بیاورید.
- مصرف حافظه: برای فایلهای حجیم، این عدد تعیین میکند که آیا میتوانید کل داده را در حافظه نگه دارید یا باید تکهتکه پردازش کنید.
برای تحلیل آمار توصیفی، describe() خروجی مفیدی میدهد. اگر با کارایی حافظه درگیرید، df.memory_usage(deep=True) جزئیات دقیقتری از مصرف هر ستون میدهد — این ابزار، در پروژههای حجیم، تصمیمگیری برای کاهش مصرف را ممکن میکند.
قبل از هر تحلیل، پنج دقیقه رویdf.info()وdf.describe()وقت بگذارید؛ این پنج دقیقه، از پنج ساعت دیباگ بعدی جلوگیری میکند.
انتخاب و فیلتر کردن داده
انتخاب و فیلتر، پرکاربردترین عملیات پانداس است. چهار الگو که در پروژههای واقعی دائماً بهکار میبرم:
۱) انتخاب ستون
# یک ستون (خروجی Series)
names = df["customer"]
# چند ستون (خروجی DataFrame)
subset = df[["customer", "total"]]
۲) فیلتر سطری با شرط
# یک شرط
big_orders = df[df["total"] > 500]
# ترکیب شرطها (پرانتز اجباری است)
filtered = df[(df["total"] > 500) & (df["customer"] == "Ali")]
# فیلتر با isin
special = df[df["customer"].isin(["Ali", "Sara"])]
دو نکتهی مهم در فیلتر که در پروژههای واقعی، بارها منبع باگ بوده:
- پرانتز اجباری در ترکیب شرطها: در پایتون،
&و|اولویت پایینتری از==و>دارند. اگر پرانتز نگذارید، شرط شما به شکل غیرمنتظرهای تجزیه میشود. - استفاده از
&و|نهandوor: در پانداس،andوorروی کل Series کار نمیکنند و خطای مبهم میدهند. همیشه از&و|استفاده کنید.
۳) انتخاب با loc و iloc
# سه سطر اول، دو ستون اول
df.iloc[:3, :2]
# سطر با برچسب خاص، ستونهای منتخب
df.loc[0:10, ["customer", "total"]]
۴) فیلتر با query
اگر شرطهای شما پیچیده است، query خواناتر است:
df.query("total > 500 and customer == 'Ali'")
df.query("total > @threshold") # استفاده از متغیر بیرونی
در پروژههای واقعی، query را در دو حالت استفاده میکنم: وقتی شرط پیچیده است (سه یا بیشتر)، و وقتی پارامترها از بیرون میآیند. برای شرطهای ساده، همان براکت و & کافی است.
تغییر، افزودن و حذف ستون
سه عملیات پرکاربرد که در پروژههای واقعی دائماً به آنها نیاز دارم:
افزودن ستون جدید با محاسبه
df["total"] = df["quantity"] * df["price"]
df["discounted"] = df["total"].apply(lambda x: x * 0.9 if x > 500 else x)
نکتهی مهم: apply راهحل سریع است ولی سریعترین نیست. برای عملیات ریاضی ساده (ضرب، جمع، شرطهای تکخطی)، از عملیات برداری استفاده کنید:
# بهجای apply
df["discounted"] = df["total"] * 0.9
df["category"] = "regular"
df.loc[df["total"] > 500, "category"] = "premium"
تفاوت سرعت بین apply و عملیات برداری، در دادهی حجیم میتواند صد برابر باشد — همان درسی که در مبحث بهینهسازی کدهای PHP هم معادلش را در کنار گذاشتن حلقههای دستی دیدهام.
تغییر نام ستونها
df = df.rename(columns={"old_name": "new_name", "customer": "client"})
حذف ستون یا سطر
df = df.drop(columns=["internal_id", "temp"])
df = df.drop(index=[0, 5])
یک نکتهی مهم: drop بهطور پیشفرض، DataFrame جدید برمیگرداند و اصل را تغییر نمیدهد. اگر میخواهید در جا تغییر کند، از inplace=True استفاده کنید — ولی در پروژههای واقعی، من ترجیح میدهم همیشه نسخهی جدید را بگیرم، چون کد خواناتر میشود و دیباگ سادهتر است.
groupby و تحلیل تجمیعی
گروهبندی، قلب تحلیل داده در پانداس است. مکانیزم آن، درست مثل GROUP BY در SQL کار میکند:
summary = df.groupby("customer").agg({
"total": ["sum", "mean", "count"],
"quantity": "sum",
})
print(summary)
سه الگوی پرکاربرد که در پروژههای واقعی به آنها برخوردهام:
۱) گروهبندی چندسطحی
df.groupby(["customer", "product"]).agg({"total": "sum"})
۲) گروهبندی و فیلتر کردن گروهها
# فقط گروههایی که جمعشان از ۱۰۰۰ بیشتر است
filtered = df.groupby("customer").filter(lambda g: g["total"].sum() > 1000)
۳) تبدیل و اعمال تابع روی هر گروه
# محاسبهی سهم هر محصول در هر مشتری
df["share"] = df.groupby("customer")["total"].transform(lambda x: x / x.sum())
transform در پروژههای واقعی بسیار بهکارم آمده: بهجای برگرداندن یک جدول خلاصه، همان تعداد سطر اولیه را با مقادیر محاسبهشده برمیگرداند. یعنی میتوانید محاسبات گروهی را بهعنوان ستون جدید به DataFrame اضافه کنید.
یک نکتهی کارایی: groupby در پانداس، از الگوریتمهای سریع برای گروهبندی روی ستونهای عددی استفاده میکند. اگر ستون گروهبندی شما رشته است، میتوانید برای افزایش سرعت، آن را به category تبدیل کنید:
df["customer"] = df["customer"].astype("category")
df.groupby("customer").agg({"total": "sum"})
این یک خط، در پروژهای با میلیون ردیف، زمان اجرا را چند برابر کاهش میدهد. اگر با دیتابیسهای SQL کار کردهاید، مشابه این رویکرد را در بهینهسازی کوئریهای MySQL دیدهاید — فقط پانداس این بهینهسازی را در سطح حافظه انجام میدهد.
Merge و Join جداول
در پروژههای واقعی، دادهی شما از چند منبع میآید. ادغام آنها، کاری است که پانداس بسیار خوب انجام میدهد. چهار نوع join که معادل SQL دارند:
# Inner join (پیشفرض)
merged = pd.merge(orders, customers, on="customer_id", how="inner")
# Left join
merged = pd.merge(orders, customers, on="customer_id", how="left")
# Right join
merged = pd.merge(orders, customers, on="customer_id", how="right")
# Outer join
merged = pd.merge(orders, customers, on="customer_id", how="outer")
چهار نکتهی مهم در merge که در پروژههای واقعی به آنها رسیدهام:
- ستون مشترک با نام متفاوت: از
left_onوright_onاستفاده کنید:
pd.merge(orders, customers, left_on="cust_id", right_on="id")
- همنام بودن ستونهای غیرکلید: اگر در هر دو DataFrame ستونی به نام
created_atباشد، پانداس بهطور پیشفرض_xو_yبه آنها اضافه میکند. ازsuffixesبرای انتخاب نامهای معنادار استفاده کنید:
pd.merge(orders, customers, on="customer_id", suffixes=("_order", "_customer"))
- بررسی نتیجهی merge: بعد از هر merge، تعداد سطرها را چک کنید. اگر خروجی از هر دو ورودی بیشتر شد، یعنی ستون کلید شما یکتا نبوده. این اتفاق در پروژههای واقعی، بیصدا رخ میدهد و میتواند دادهی شما را چند برابر کند.
- استفاده از validate: پانداس پارامتر
validateدارد که یکی از مقادیر"one_to_one"،"one_to_many"،"many_to_one"یا"many_to_many"را میپذیرد. با این پارامتر، مطمئن میشوید merge شما همان نوع رابطهای است که انتظار دارید:
pd.merge(orders, customers, on="customer_id", validate="many_to_one")
مدیریت دادههای گمشده
دادههای واقعی، همیشه ناقص هستند. پانداس ابزارهای خوبی برای تشخیص و مدیریت این دادهها دارد:
# تشخیص
df.isna().sum() # تعداد گمشده در هر ستون
df.isna().sum() / len(df) # درصد گمشده
# حذف
df_clean = df.dropna() # حذف همهی سطرهای دارای گمشده
df_clean = df.dropna(subset=["total"]) # فقط بر اساس ستونهای مشخص
# پر کردن
df["total"] = df["total"].fillna(0)
df["quantity"] = df["quantity"].fillna(df["quantity"].median())
سه تصمیم مهم در مدیریت دادههای گمشده که در پروژههای واقعی به آنها رسیدهام:
| استراتژی | مناسب برای | هشدار |
|---|---|---|
| حذف سطرها (dropna) | گمشدههای کم | در دادهی حجیم، ممکن است ۳۰٪ سطرها را از دست بدهید |
| پر کردن با صفر | دادههای شمارشی | در دادههای مالی، صفر ممکن است معنای اشتباهی بدهد |
| پر کردن با میانگین/میانه | دادههای عددی پیوسته | میانگین به outlier حساس است؛ میانه انتخاب بهتری است |
| پر کردن با مقدار قبلی/بعدی | سریهای زمانی | در دادههای غیر زمانی، معنای نادرست میدهد |
یک نکتهی مهم: هرگز بیفکر از fillna(0) استفاده نکنید. در دادههای مالی، صفر ممکن است معنای «بدون تراکنش» بدهد در حالی که مقدار واقعاً گمشده بوده. در تجربهی من، ۹۰٪ باگهای تحلیل که از دادهی گمشده میآید، ناشی از پر کردن بدون تفکر است. همیشه اول بپرسید: «اگر این داده وجود نداشت، یعنی صفر است، یعنی گمشده، یا یعنی مقدار نامعتبر؟»
در دادههای واقعی، گمشده بودن خودش یک داده است؛ حذف یا پرکردن آن، بخشی از تحلیل است، نه یک پاکسازی صرف.
کارایی، حافظه و vectorization
سرعت پانداس از عملیات برداری میآید، نه از حلقهها. اگر با حلقه روی DataFrame پیمایش کنید، سرعت شما به پایتون خالص برمیگردد — یعنی کند. چهار قاعدهی مهم در پروژههای حجیم:
۱) همیشه برداری بیندیشید
# کند
for i in range(len(df)):
df.loc[i, "total"] = df.loc[i, "quantity"] * df.loc[i, "price"]
# سریع
df["total"] = df["quantity"] * df["price"]
تفاوت این دو، روی دادهی یک میلیون ردیفی، میتواند از چند دقیقه به چند میلیثانیه برسد. اگر از حلقه استفاده میکنید، همیشه بهدنبال راه برداری باشید. اگر واقعاً نمیتوانید برداری کنید، حداقل از iterrows پرهیز کنید و بهجایش itertuples را امتحان کنید که چند برابر سریعتر است.
۲) نوع داده را کاهش دهید
# بهجای int64 (پیشفرض)
df["quantity"] = df["quantity"].astype("int32")
# برای ستونهای رشتهای با مقادیر محدود
df["city"] = df["city"].astype("category")
این کار در پروژههای حجیم، مصرف حافظه را نصف یا کمتر میکند و در نتیجه، سرعت عملیات هم بیشتر میشود. اگر فایل شما بیش از حافظه است، این تکنیکها را جدی بگیرید.
۳) برای فایلهای بزرگ، chunked processing
chunks = []
for chunk in pd.read_csv("huge.csv", chunksize=100_000, encoding="utf-8"):
result = chunk.groupby("customer")["total"].sum()
chunks.append(result)
final = pd.concat(chunks).groupby(level=0).sum()
اگر فایل چند گیگابایتی دارید و نمیتوانید کل آن را در حافظه بار کنید، این الگو راهحل است. اگر با کار با فایلهای حجیم در پایتون آشنا نیستید، کار با فایلها در پایتون تکنیکهای مشابه را برای فایل خالص پایتونی توضیح میدهد.
۴) از ابزارهای حرفهای استفاده کنید
برای پروژههای بسیار سنگین، سه گزینه:
- Polars: جایگزین مدرن پانداس که در پردازشهای حجیم چند برابر سریعتر است.
- Dask: پردازش دادههای بزرگتر از حافظه با API مشابه پانداس.
- PyArrow: برای خواندن سریع فایلهای Parquet و ارتباط با ابزارهای دیگر.
در پروژههای واقعی، تا وقتی داده زیر چند میلیون ردیف است، پانداس کافی است. اگر مرز رد شد، قبل از پیچیدن به Dask، حتماً Polars را امتحان کنید — چون معمولاً همان سرعت را با پیچیدگی کمتر میدهد.
اشتباهاتی که در پروژههای واقعی دیدهام
در بازبینی پروژههای پانداس، این اشتباهات را زیاد دیدهام و هرکدام، یک درس عملی است:
- SettingWithCopyWarning را نادیده گرفتن: وقتی از یک DataFrame زیرمجموعه میگیرید و روی آن تغییر میدهید، پانداس هشدار میدهد ولی اجرا میکند — که ممکن است تغییرات روی DataFrame اصلی اعمال نشود. همیشه
.copy()را در جای مناسب استفاده کنید. - تغییر ستونها در حلقه: بهجای عملیات برداری، از حلقه استفاده میکنند. صد برابر کندتر.
- بیتوجهی به type داده: ستون عددی که بهعنوان
objectذخیره شده باشد، محاسبات را کند و نادرست میکند. همیشهdf.dtypesرا چک کنید. - استفاده از
appendدر حلقه:df = df.append(new_row)در حلقه، در هر تکرار یک DataFrame جدید میسازد و برای دادهی حجیم بسیار کند است. راهحل: جمعآوری در لیست و سپسpd.concat. - اجرای merge بدون بررسی نتیجه: همانطور که گفتم، اگر کلید شما یکتا نباشد، نتیجه چند برابر میشود. همیشه تعداد سطرهای قبل و بعد را چک کنید.
- fillna با صفر بیفکر: باعث مخدوش شدن آمار میشود. همیشه اول معنای گمشده بودن را بفهمید.
- مقایسهی شناورها با
==: در پانداس، مقایسهی مستقیم مقادیر اعشاری به دلیل نمایش باینری میتواند نادرست باشد. ازnp.iscloseاستفاده کنید. - نادیده گرفتن memory usage: در دادههای حجیم، عدم توجه به مصرف حافظه، در ساعت بحرانی به
MemoryErrorمیرسد. اگر با این خطا روبرو شدهاید، رفع خطای MemoryError در پایتون راههای تشخیص و رفع را نشان میدهد. - نبود backup بعد از تغییرات مهم: وقتی DataFrame را تغییر میدهید، اصل داده را از دست میدهید. در تحلیلهای پیچیده، یک
df.copy()قبل از هر تغییر مهم، روز نجاتبخش است.
یک توصیهی عملی از تجربه: در پروژههای تحلیل داده، عادت کنید هر تغییر مهم روی DataFrame را در یک مرحلهی جدا انجام دهید و در آخر، یک df.to_csv("step_name.csv") برای ذخیرهی وضعیت بگیرید. این کار، در صورت اشتباه در مراحل بعدی، امکان برگشت به عقب را میدهد — همان انضباط نسخهبندی که در گیت در پروژههای وردپرسی برای کد توصیه کردهام، برای داده هم صادق است.
از اینجا به کجا؟
پانداس، از یک DataFrame ساده شروع میشود ولی در پروژههای واقعی، به ستون فقرات جریان داده تبدیل میشود. سه نکتهی اصلی که در این مقاله به آنها رسیدیم: اول، عملیات برداری، سرعت پانداس را میسازد — هر جا امکان دارد، از حلقه پرهیز کنید؛ دوم، درک درست ساختمان داده (Series، DataFrame، تفاوت loc و iloc)، جلوی بسیاری از باگها را میگیرد؛ سوم، مدیریت دادههای گمشده یک تصمیم تحلیلی است، نه یک پاکسازی ساده — پر کردن بیفکر، تحلیل را آلوده میکند.
اگر امروز میخواهید شروع کنید، سه کار کوچک پیشنهاد میکنم: یک فایل CSV واقعی (حتی از فروش خودتان) بگیرید و با read_csv بخوانید، ساختار و نوع دادهها را با df.info() بررسی کنید، و یک گزارش ساده با groupby بسازید. همین پروژهی کوچک، بیشتر از ده ساعت ویدیو، پانداس را در ذهن شما جا میاندازد. مسیر طبیعی بعدی، تحلیل داده با کتابخانههای مصورسازی، یا ورود به یادگیری ماشین است که پانداس، پیشنیاز آن است. اگر تجربهای از پانداس در پروژههای خودتان دارید — مخصوصاً اگر با دادهی حجیم یا مسئلهی کارایی روبرو شدهاید — در دیدگاهها بنویسید؛ همین نکتههای میدانی، برای خوانندهی بعدی از هر مستند رسمی ارزشمندتر است. 🐼