Kahibaro
Discord Login Register

کار با داده‌ها

مفاهیم پایهٔ «داده» در پایتون

در علم داده، تقریباً همه‌چیز با «داده» شروع می‌شود. در این فصل منظورمان از «کار با داده‌ها» بیشتر کار با داده‌های جدولی (مثل فایل‌های CSV یا خروجی پایگاه‌داده‌ها) است؛ چیزی شبیه جدول‌های Excel.

برای شروع، چند مفهوم پایه را روشن کنیم:

در پایتون، قبل از استفاده از کتابخانه‌هایی مثل NumPy و pandas، می‌توانیم با همین ساختارهای ساده کار کنیم.

ساختارهای معمول برای نگهداری داده جدولی

چند الگوی رایج برای نگهداری یک جدول در پایتون بدون pandas:

لیستِ ردیف‌ها (هر ردیف یک لیست)

مثال یک جدول خیلی سادهٔ نمرات:

grades = [
    ["Ali", 18.5, "Math"],
    ["Sara", 19.0, "Math"],
    ["Reza", 15.0, "Physics"],
]

این ساختار ساده است، اما خواندن ستون‌ها با نام کمی سخت است (باید حفظ کنید ستون ۰ نام است، ستون ۱ نمره، …).

لیستِ دیکشنری‌ها (هر ردیف یک دیکشنری)

خواناتر و نزدیک‌تر به داده‌های دنیای واقعی:

grades = [
    {"name": "Ali",  "score": 18.5, "lesson": "Math"},
    {"name": "Sara", "score": 19.0, "lesson": "Math"},
    {"name": "Reza", "score": 15.0, "lesson": "Physics"},
]

حالا:

این الگو در بسیاری از اسکریپت‌های سادهٔ علم داده (بدون pandas) کاملاً کاربردی است.

خواندن داده از فایل متنی ساده (مثل CSV کوچک)

جزئیات کامل خواندن/نوشتن فایل در فصلِ «کار با فایل‌ها» می‌آید؛ اینجا فقط روی تبدیل متن به دادهٔ قابل‌کار تمرکز می‌کنیم.

فرض کنید فایل grades.csv داریم:

name,score,lesson
Ali,18.5,Math
Sara,19.0,Math
Reza,15.0,Physics

یک راه ساده برای تبدیل آن به «لیستِ دیکشنری‌ها»:

grades = []
with open("grades.csv", "r", encoding="utf-8") as f:
    lines = f.readlines()
header = lines[0].strip().split(",")   # ['name', 'score', 'lesson']
for line in lines[1:]:  # رد شدن از ردیف عنوان
    parts = line.strip().split(",")    # ['Ali', '18.5', 'Math']
    row = {}
    for i, col_name in enumerate(header):
        row[col_name] = parts[i]
    grades.append(row)
print(grades)

خروجی تقریبی:

[
  {'name': 'Ali', 'score': '18.5', 'lesson': 'Math'},
  {'name': 'Sara', 'score': '19.0', 'lesson': 'Math'},
  {'name': 'Reza', 'score': '15.0', 'lesson': 'Physics'}
]

فعلاً همه‌چیز str است؛ بعداً می‌توانیم بعضی ستون‌ها را به عدد تبدیل کنیم.

تبدیل نوع داده (مثلاً از متن به عدد)

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

for row in grades:
    row["score"] = float(row["score"])

حالا row["score"] یک float است که می‌توانیم روی آن محاسبات انجام دهیم.

مثال: محاسبهٔ میانگین نمره‌ها:

total = 0
count = 0
for row in grades:
    total += row["score"]
    count += 1
average = total / count
print("Average score:", average)

این الگوی «جمع کردن و شمردن» یکی از رایج‌ترین کارها در پردازش داده است.

فیلتر کردن ردیف‌ها (انتخاب زیرمجموعهٔ داده)

در علم داده خیلی زیاد پیش می‌آید که بگوییم «فقط ردیف‌هایی را می‌خواهم که …».

مثال: همهٔ نمره‌های درس ریاضی:

math_grades = []
for row in grades:
    if row["lesson"] == "Math":
        math_grades.append(row)
print(math_grades)

یا کوتاه‌تر با لیست‌کامپرهِنشن:

math_grades = [row for row in grades if row["lesson"] == "Math"]

مثال دیگر: فقط نمره‌های بالاتر از ۱۷:

high_scores = [row for row in grades if row["score"] > 17]

انتخاب ستون (ویژگی)‌های خاص

گاهی فقط یک ستون از داده را لازم داریم (مثلاً فقط نمره‌ها یا فقط نام‌ها).

scores = [row["score"] for row in grades]
names  = [row["name"]  for row in grades]
print(scores)  # مثلاً [18.5, 19.0, 15.0]
print(names)   # ['Ali', 'Sara', 'Reza']

از روی scores می‌توانیم حداقل، حداکثر، میانگین و … را حساب کنیم:

minimum = min(scores)
maximum = max(scores)
average = sum(scores) / len(scores)
print("Min:", minimum)
print("Max:", maximum)
print("Avg:", average)

گروه‌بندی سادهٔ داده‌ها (grouping) بدون pandas

یکی از کارهای بسیار رایج در علم داده، خلاصه کردن داده‌ها بر اساس یک دسته‌بندی است. مثلاً:

با ساختارهای پایهٔ پایتون هم می‌توانیم یک نسخهٔ ساده از این کار را انجام دهیم.

مثال: می‌خواهیم «میانگین نمرهٔ هر درس» را حساب کنیم.

۱. ساخت دیکشنری برای جمع و تعداد

sum_by_lesson = {}    # کل نمره‌ها برای هر درس
count_by_lesson = {}  # تعداد ردیف‌ها برای هر درس
for row in grades:
    lesson = row["lesson"]
    score = row["score"]
    if lesson not in sum_by_lesson:
        sum_by_lesson[lesson] = 0
        count_by_lesson[lesson] = 0
    sum_by_lesson[lesson] += score
    count_by_lesson[lesson] += 1

۲. محاسبهٔ میانگین برای هر درس

avg_by_lesson = {}
for lesson in sum_by_lesson:
    avg_by_lesson[lesson] = sum_by_lesson[lesson] / count_by_lesson[lesson]
print(avg_by_lesson)

مثلاً خروجی:

{'Math': 18.75, 'Physics': 15.0}

این نوع «گروه‌بندی» در pandas و کتابخانه‌های حرفه‌ای‌تر خیلی راحت‌تر انجام می‌شود، اما درک آن با دیکشنری‌ها کمک می‌کند منطق پشت پرده را ببینیم.

پاک‌سازی سادهٔ داده‌ها (Cleaning)

در دادهٔ واقعی معمولاً با مشکلاتی مثل مقدار خالی، تایپ اشتباه یا فرمت نامنظم روبه‌رو می‌شویم. اینجا چند کار ساده و پرکاربرد را می‌بینید.

فرض کنید چند ردیف خراب داریم:

raw_grades = [
    {"name": " Ali ", "score": "18.5", "lesson": "Math"},
    {"name": "Sara",  "score": "",     "lesson": "Math"},     # نمره خالی
    {"name": "Reza",  "score": "NaN",  "lesson": "Physics"},  # مقدار نا‌معتبر
]

تمیز کردن فضاهای اضافی متن‌ها

for row in raw_grades:
    row["name"] = row["name"].strip()

حالا " Ali ""Ali".

تبدیل امن رشته به عدد

اگر مستقیماً float("") را اجرا کنیم، خطا می‌گیریم. یک تابع کوچک کمکی می‌نویسیم:

def to_float_or_none(text):
    text = text.strip()
    if text == "" or text.lower() == "nan":
        return None
    return float(text)
for row in raw_grades:
    row["score"] = to_float_or_none(row["score"])
print(raw_grades)

حالا نمره‌های خراب تبدیل به None شده‌اند.

حذف ردیف‌های دارای مقدار گم‌شده (در صورت نیاز)

گاهی برای سادگی، ردیف‌هایی که مقدار مهمی را ندارند حذف می‌کنیم:

clean_grades = []
for row in raw_grades:
    if row["score"] is not None:
        clean_grades.append(row)
print(clean_grades)

در پروژه‌های جدی‌تر تصمیم‌گیری دربارهٔ داده‌های ناقص مهم و ظریف است؛ اما این الگو برای اسکریپت‌های ساده و مثال‌های آموزشی کافی است.

مرتب‌سازی داده‌ها

گاهی می‌خواهیم ردیف‌ها را بر اساس یک ستون مرتب کنیم؛ مثلاً از بیشترین نمره تا کمترین.

مرتب‌سازی با `sorted` و `key`

فرض کنید grades یک لیست از دیکشنری‌هاست و ستون score عددی است.

sorted_by_score = sorted(grades, key=lambda row: row["score"])
sorted_by_score_desc = sorted(grades, key=lambda row: row["score"], reverse=True)

یا مثلاً مرتب‌سازی حروفی بر اساس name:

sorted_by_name = sorted(grades, key=lambda row: row["name"])

خلاصه‌سازی داده‌ها با حلقه‌ها

در بسیاری از مسائل سادهٔ علم داده، کار شما ترکیبی از این ۴ کار خواهد بود:

  1. خواندن داده (از فایل یا منبع دیگر) و تبدیل به ساختارهایی مثل لیست و دیکشنری.
  2. پاک‌سازی قسمت‌های خراب، مقادیر خالی و تبدیل نوع داده‌ها.
  3. فیلتر و گروه‌بندی داده بر اساس شرط‌ها (فقط یک درس، فقط یک شهر، فقط سن بالای ۲۰، …).
  4. خلاصه‌سازی با محاسبهٔ چیزهایی مثل:
    • مجموع: $ \text{sum} $
    • میانگین: $ \text{average} = \dfrac{\text{sum}}{\text{count}} $
    • کمینه و بیشینه
    • تعداد ردیف‌ها

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

یک مثال کوچکِ کاملِ «کار با داده»

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

city,amount
Tehran,100000
Tehran,250000
Shiraz,80000
Tehran,120000
Shiraz,60000

می‌خواهیم «مجموع فروش هر شهر» را حساب کنیم.

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

sales = []
with open("sales.csv", "r", encoding="utf-8") as f:
    lines = f.readlines()
header = lines[0].strip().split(",")
for line in lines[1:]:
    parts = line.strip().split(",")
    row = {}
    for i, col in enumerate(header):
        row[col] = parts[i]
    sales.append(row)

۲. تبدیل مبلغ به عدد

for row in sales:
    row["amount"] = int(row["amount"])

۳. خلاصه‌سازی (مجموع فروش هر شهر)

total_by_city = {}
for row in sales:
    city = row["city"]
    amount = row["amount"]
    if city not in total_by_city:
        total_by_city[city] = 0
    total_by_city[city] += amount
print(total_by_city)

خروجی:

{'Tehran': 470000, 'Shiraz': 140000}

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

جمع‌بندی

در این بخش دیدید که:

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

Views: 5

Comments

Please login to add a comment.

Don't have an account? Register now!