سرنخ — خودآموز برنامه‌نویسی برای هوش مصنوعی (مقدماتی)

فصل ۸ از ۱۰

پیشرفت ترم
۰٪

ترم ۲ · داده: دیدن، تمیز کردن، فهمیدن

«اول داده را ببین»: تحلیلِ اکتشافی

فصل ۸پیش‌نمایش رایگان
۹ دقیقه مطالعه فصل ۸

در این فصل چه یاد می‌گیری#

ابزارها را داری: خلاصه، گروه‌بندی، نمودار. این فصل آن‌ها را در یک فرآیند می‌چیند. تحلیلِ اکتشافی یعنی قبل از هر مدل و هر نتیجه‌گیری، چند سؤالِ ثابت از داده بپرسی. در این فصل آن سؤال‌ها را یاد می‌گیری، مقدارهای پرت را پیدا می‌کنی و می‌فهمی چرا حذفشان معمولاً اشتباه است، و مهم‌تر از همه: می‌بینی یک همبستگیِ ۰٫۶۳۵ چطور می‌تواند تصویرِ کاملاً غلطی بدهد — و با یک فیلترِ ساده به ۰٫۸۹۵ برسد.

یک ذره‌بین روی یک ابرِ نقطه که یک دسته از نقطه‌ها با علامتِ متفاوت مشخص شده‌اند

آخر این فصل می‌توانی:

  • پنج سؤالِ ثابتِ تحلیلِ اکتشافی را روی هر دیتاستِ تازه‌ای بپرسی
  • مقدارهای پرت را با قاعدهٔ IQR پیدا کنی و آگاهانه دربارهٔ آن‌ها تصمیم بگیری
  • همبستگی را بخوانی و بگویی دقیقاً چه چیزی را نمی‌گوید
  • یک متغیرِ پنهان را پیدا کنی که رابطهٔ دو ستونِ دیگر را تحریف می‌کند

قبل از شروع#

از فصل ۶: groupby و agg.

از فصل ۷: هیستوگرام، نمودارِ پراکندگی و corr().

از فصل ۳: describe() و چارک‌ها.

📓 نوت‌بوک: نوت‌بوک این فصل را در Colab باز کن — همهٔ کدهای این فصل آماده و به‌ترتیب داخلش هست.

۱. پنج سؤالِ ثابت#

تحلیلِ اکتشافی الهام نمی‌خواهد؛ یک فهرست است. هر بار که دیتاستِ تازه‌ای می‌گیری، همین پنج سؤال را بپرس:

  1. چقدر است و چه شکلی است؟shape، dtypes، head
  2. چقدرش گم است؟isna().sum()
  3. هر ستون چه توزیعی دارد؟describe، value_counts، هیستوگرام
  4. چه چیزی عجیب است؟ — مقدارِ غیرممکن، مقدارِ پرت، دستهٔ تک‌عضوی
  5. ستون‌ها با هم چه رابطه‌ای دارند؟corr، groupby، پراکندگی

سؤالِ اول تا سوم را در فصل‌های ۳ تا ۷ انجام دادی. این فصل چهار و پنج است — سخت‌ترینشان، چون جوابشان عدد نیست، قضاوت است.

۲. مقدارِ پرت: قاعدهٔ IQR#

import pandas as pd

df = pd.read_csv("laptops_clean.csv")

q1 = df["price"].quantile(0.25)
q3 = df["price"].quantile(0.75)
iqr = q3 - q1
low = q1 - 1.5 * iqr
high = q3 + 1.5 * iqr

print("چارک اول:", round(q1))
print("چارک سوم:", round(q3))
print("مرز پایین:", round(low))
print("مرز بالا:", round(high))
چارک اول: 19000000
چارک سوم: 31700000
مرز پایین: -50000
مرز بالا: 50750000

متدِ quantile(0.25) همان عددی را می‌دهد که در خروجیِ describe() فصلِ ۳ زیرِ برچسبِ 25% دیدی: عددی که یک‌چهارمِ داده زیرِ آن است. اینجا جداگانه می‌گیریمش، چون می‌خواهیم رویش حساب کنیم نه فقط نگاهش کنیم.

IQR فاصلهٔ چارکِ اول تا سوم است — بازه‌ای که نیمهٔ میانیِ داده در آن است. قاعدهٔ متعارف می‌گوید هر چیزی که بیش از یک‌ونیم برابرِ IQR بیرونِ این بازه باشد، «پرت» است.

توجه کن مرزِ پایین منفی درآمد، یعنی از این طرف هیچ پرتی نداریم — که منطقی است، قیمت منفی نمی‌شود.

outliers = df[(df["price"] < low) | (df["price"] > high)]

print("تعداد پرت:", len(outliers))
print(outliers["brand"].value_counts())
تعداد پرت: 9
brand
اپل    9
Name: count, dtype: int64

و اینجا مهم‌ترین درسِ فصل است. هر نُه مقدارِ پرت مالِ یک برند است.

اگر کورکورانه قاعده را اجرا می‌کردی — «مقدارِ پرت را حذف کن» — نُه لپ‌تاپِ گران‌قیمت را دور می‌ریختی، در حالی که هیچ‌کدامشان خطا نیستند. آن‌ها یک زیرگروهِ واقعیاند.

📏 اندازه بگیر: قاعدهٔ کار با مقدارِ پرت، در یک جمله: اول بپرس این چیست، بعد تصمیم بگیر. سه حالتِ کاملاً متفاوت وجود دارد و کدشان یکی است ولی جوابشان نه — (۱) خطای ثبت مثلِ سالِ ۲۲۰۵؛ حذف یا تصحیح. (۲) زیرگروهِ واقعی مثلِ همین اپل؛ هرگز حذف نکن، به‌جایش یک ستونِ دسته‌بندی بساز. (۳) رویدادِ نادرِ واقعی؛ نگه‌دار و در گزارش صریح بگو. value_counts روی ردیف‌های پرت، ارزان‌ترین راهِ فهمیدنِ اینکه با کدام حالت طرفی.

۳. همبستگی، و آنچه نمی‌گوید#

print(df[["year", "ram_gb", "price"]].corr().round(3))
         year  ram_gb  price
year    1.000   0.041  0.635
ram_gb  0.041   1.000  0.290
price   0.635   0.290  1.000

همبستگی می‌گوید دو متغیر چقدر هم‌جهت حرکت می‌کنند: نزدیک به ۱+ یعنی با هم بالا می‌روند، نزدیک به ۱- یعنی یکی بالا و دیگری پایین، نزدیک به صفر یعنی رابطهٔ خطیای دیده نمی‌شود.

سه چیزی که این جدول نمی‌گوید و همه فرض می‌کنند می‌گوید:

  • علیت. ۰٫۶۳۵ بینِ سال و قیمت نمی‌گوید سالِ ساخت باعثِ قیمت است. می‌تواند برعکس باشد، یا هر دو از عاملِ سومی بیایند.
  • رابطهٔ غیرخطی. همبستگیِ نزدیکِ صفر فقط یعنی رابطهٔ خطی ضعیف است. دو متغیر می‌توانند رابطهٔ کاملاً محکمِ منحنی داشته باشند و همبستگی‌شان صفر باشد. همیشه نمودار را هم ببین.
  • اهمیت. ۰٫۲۹ بینِ حافظه و قیمت «کم» است، ولی روی ۲۳۸ ردیف می‌تواند کاملاً واقعی باشد. کوچکیِ عدد یعنی رابطه ضعیف است، نه اینکه وجود ندارد.

🌱 ریشه‌اش کجاست: جملهٔ «همبستگی علیت نیست» را همه شنیده‌اند و کم‌تر کسی می‌داند دقیقاً چرا. ریشه، ترم ۶ فصل ۸ — نمونه‌گیری، و چطور با آمار دروغ می‌گویند با مثال‌های واقعی نشان می‌دهد چطور دو چیزِ کاملاً بی‌ربط می‌توانند همبستگیِ بالا داشته باشند.

۴. متغیرِ پنهان: وقتی یک زیرگروه رابطه را پنهان می‌کند#

بیایید فرضیه‌ای را بسنجیم. شاید آن همبستگیِ ۰٫۶۳۵ به‌خاطرِ اپل باشد — اگر سهمِ اپل در سال‌های اخیر بیشتر شده باشد، بخشی از «گران‌شدن» فقط تغییرِ ترکیبِ برندهاست.

df["is_apple"] = df["brand"] == "اپل"
print(df.groupby("year")["is_apple"].mean().round(3))
year
2016    0.133
2017    0.091
2018    0.160
2019    0.130
2020    0.057
2021    0.194
2022    0.050
2023    0.107
2024    0.125
Name: is_apple, dtype: float64

فرضیه رد شد: سهمِ اپل بالا و پایین می‌رود ولی روندِ صعودی ندارد. پس گران‌شدن از تغییرِ ترکیبِ برندها نمی‌آید.

ولی حالا یک کارِ دیگر بکنیم — اپل را کاملاً کنار بگذاریم و همان همبستگی را دوباره حساب کنیم:

no_apple = df[df["brand"] != "اپل"]

print("همبستگی با اپل:", df[["year", "price"]].corr().round(3).iloc[0, 1])
print("همبستگی بدون اپل:", no_apple[["year", "price"]].corr().round(3).iloc[0, 1])
print(no_apple.groupby("year")["price"].mean().round(0))
همبستگی با اپل: 0.635
همبستگی بدون اپل: 0.895
year
2016    14338462.0
2017    15820000.0
2018    18380952.0
2019    20455000.0
2020    23909091.0
2021    26308000.0
2022    28952632.0
2023    32752000.0
2024    33742857.0
Name: price, dtype: float64

همبستگی از ۰٫۶۳۵ به ۰٫۸۹۵ رفت. و روندِ سالانه حالا کاملاً یکنواخت است — بدونِ آن افتِ ۲۰۲۲ که در فصلِ ۷ دیدیم.

چه اتفاقی افتاد؟ اپل قیمت‌هایی دارد که در همهٔ سال‌ها بالاست، پس در هر سال یک پراکندگیِ بزرگ اضافه می‌کند که رابطهٔ زیرین را می‌پوشاند. اپل خطا نبود، پرتِ حذف‌کردنی هم نبود — یک جمعیتِ متفاوت بود که با بقیه قاطی شده بود.

قبل از ادامه، جواب بده: پس کدام عدد درست است، ۰٫۶۳۵ یا ۰٫۸۹۵؟ جواب: هر دو، برای دو سؤالِ متفاوت. اگر می‌پرسی «در کلِ بازار قیمت با سال چه رابطه‌ای دارد» جواب ۰٫۶۳۵ است. اگر می‌پرسی «برای یک لپ‌تاپِ معمولی» جواب ۰٫۸۹۵ است. عدد بدونِ سؤال معنا ندارد — و این دقیقاً همان چیزی است که کلِ این دوره روی آن بنا شده.

چک کن: هر دو عدد را خودت اجرا کن. اگر عددِ دومی از اولی کمتر شد، احتمالاً != را == نوشته‌ای و داری فقط روی اپل حساب می‌کنی.

۵. یک خطای واقعی: همبستگی روی ستونِ غیرعددی#

df[["brand", "price"]].corr()
ValueError: could not convert string to float: 'اپل'

corr() فقط با عدد کار می‌کند. برای رابطهٔ یک ستونِ دسته‌ای با یک ستونِ عددی، ابزارِ درست groupby است، نه همبستگی — دقیقاً همان کاری که در فصلِ ۶ کردیم.

🔧 اگر کار نکرد: اگر corr() روی کلِ جدول جواب داد ولی ستون‌هایی که انتظار داشتی در نتیجه نبودند، pandas بی‌سروصدا ستون‌های غیرعددی را کنار گذاشته. همیشه چک کن نتیجهٔ corr() چند ستون دارد — اگر کمتر از انتظارت بود، یک ستونِ «عددی» در واقع متن است.

🤖 از دستیارت بپرس: «یک مثالِ واقعی از دو متغیر بزن که همبستگیِ بالا دارند ولی هیچ رابطهٔ علّی‌ای ندارند، و توضیح بده متغیرِ پنهانشان چیست.» جوابش را با کاری که در بخشِ ۴ کردیم مقایسه کن. اگر مثالی زد که متغیرِ پنهانش را نگفت، دوباره بپرس — نیمهٔ دوم جواب مهم‌تر است.

واژه‌های تازهٔ این فصل#

کلمه تلفظ به حروف فارسی یعنی چه
EDA ای‌دی‌اِی تحلیلِ اکتشافی: پرسیدنِ سؤال‌های ثابت از دادهٔ تازه
IQR آی‌کیو‌آر فاصلهٔ چارکِ اول تا سوم؛ بازهٔ نیمهٔ میانیِ داده
outlier اوت‌لایِر مقداری که خیلی از بقیه دور است — خطا، زیرگروه، یا رویدادِ نادر
confounder کان‌فاوندِر متغیرِ پنهانی که رابطهٔ دو متغیرِ دیگر را تحریف می‌کند

تمرین‌ها

اول خودت فکر کن یا امتحان کن — بعد اینجا را باز کن.

در فصل بعد#

تا اینجا با ستون‌های عددی و دسته‌ای کار کردی. ولی بخشِ بزرگی از دادهٔ واقعی متن است — نظرِ کاربر، عنوانِ آگهی، توضیحِ محصول. و متنِ فارسی مسائلِ خودش را دارد که هیچ آموزشِ انگلیسی‌ای به آن نمی‌پردازد: نیم‌فاصله، اعراب، ارقامِ چندشکلی، و کلمه‌هایی که در ظاهر یکی‌اند و در یونیکد نه. فصلِ بعد ابزارِ حرفه‌ایِ این کار را می‌آورد.

به آخر این فصل رسیدی!

اگر ساختی و جواب داد، این دکمه مال توست.