بررسی خطاها

ما باید بتوانیم کد sitka_highs_lows.py را برای اطّلاعات هر نقطه‌ی جغرافیایی استفاده کنیم. امّا برخی ایستگاه‌های هواشناسی داده‌های متفاوتی را جمع‌آوری می‌کنند و برخی ممکن است گاهی نتوانند داده‌های لازم را گرد هم آوردند. فقدان داده‌ها به وقوع استثنا منجر می‌شوند و برنامه‌های ما را از کار می‌اندازند مگر این که آن‌ها را به درستی مدیریت کنیم.

برای مثال ببینیم که در صورت تلاش برای تولید نمودار دما برای دره‌ی مرگ در کالیفرنیا چه رخ می‌دهد. فایل death_valley_2018_simple.csv را به پوشه‌ای که داده‌های برنامه‌های این فصل قرار داد منتقل کنید.

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

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
import csv

filename = 'data/death_valley_2018_simple.csv'

with open(filename) as f:
    reader = csv.reader(f)
    header_row = next(reader)

    for index, column_header in enumerate(header_row):
        print(index, column_header)

خروجی چنین است:

1
2
3
4
5
6
7
0 STATION
1 NAME
2 DATE
3 PRCP
4 TMAX
5 TMIN
6 TOBS

جایگاه تاریخ همانند قبل شاخص ۲ است. امّا جایگاه دماهای کمینه و بیشینه ۴ و ۵ است پس باید شماره‌ی شاخص‌ها را در برنامه‌ی خود تغییر دهیم تا این جایگاه‌های جدید اعمال شوند. به جای قرائت دمای میانگین برای یک روز، این ایستگاه TOBS را ارسال می‌کند که بیانگر زمان خاص مشاهده و خواندن داده است.

من یکی از قرائت‌های دما را از این فایل حذف کرده‌ام تا نشان دهم که با فقدان داده‌ای در فایل چه رخ می‌دهد. با در نظر گرفتن تغییراتی که در شماره‌ی شاخص‌ها در بالا اشاره شد، برنامه‌ی sitka_highs_lows.py را برای تولید نموداری برای دره‌ی مرگ تغییر دهید و ببینید چه رخ می‌دهد:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
--snip--

filename = 'data/death_valley_2018_simple.csv'

with open(filename) as f:
    --snip--

    # Get dates, and high and low temperatures from this file.
    dates, highs, lows = [], [], []
    for row in reader:
        current_date = datetime.strptime(row[2], '%Y-%m-%d')
        high = int(row[4])
        low = int(row[5])
        dates.append(current_date)
        --snip--

شاخص‌ها را برای تطابق با جایگاه TMAX و TMIN این فایل تغییر می‌دهیم.

زمانی که دوباره برنامه را اجرا می‌کنیم به خطا برمی‌خوریم؛ چنان‌که در آخرین خط خروجی زیر نمایان است:

1
2
3
4
Traceback (most recent call last):
  File "death_valley_highs_lows.py", line 15, in <module>
      high = int(row[4])
ValueError: invalid literal for int() with base 10: ''

این خروجی نشان می‌دهد که پایتون نمی‌تواند بیشینه‌ی دمای یکی از روزها را پردازش کند زیرا تبدیل رشته‌ی خالی ('') به عدد صحیح ممکن نیست. به جای گشتن به دنبال داده‌ی مفقود و فهمیدن این که کدام قرائت جا افتاده، موارد فقدان داده را مستقیماً مدیریّت می‌کنیم.

زمانی که مقدارها را از فایل CSV می‌خوانیم کد بررسی خطا را اجرا می‌کنیم تا استثناهای احتمالی را مدیریت کنیم. این کار به این صورت است:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
--snip--

filename = 'data/death_valley_2018_simple.csv'

with open(filename) as f:
    --snip--

    for row in reader:
        current_date = datetime.strptime(row[2], '%Y-%m-%d')
        try:
            high = int(row[4])
            low = int(row[5])
        except ValueError:
            print(f"Missing data for {current_date}")
        else:
            dates.append(current_date)
            highs.append(high)
            lows.append(low)

    # Plot the high and low temperatures.
    --snip--

    # Format plot.
    title = "Daily high and low temperatures - 2018\nDeath Valley, CA"
    plt.title(title, fontsize=20)
    plt.xlabel('', fontsize=16)
    --snip--

هنگام بررسی هر سطر سعی می‌کنیم که تاریخ و دمای بیشینه و کمینه را استخراج کنیم. اگر داده‌ای موجود نباشد پایتون اعلام خطای ValueError می‌کند و برای مدیریت آن پیام خطایی شامل تاریخ داده‌ی مفقود چاپ می‌کند. حلقه پردازش سطر بعدی را پس از چاپ پیام خطا ادامه می‌دهد. اگر تمام داده‌ها بدون خطا به دست آیند بلوک else اجرا خواهد شد و داده به لیست‌های متناسب افزوده می‌شوند. چون اطّلاعات یک موقعیّت جدید را چاپ می‌کنیم عنوان را برای آوردن نام محل جدید در نمودار به‌روز می‌کنیم و اندازه‌ی قلم را کوچکتر می‌کنیم تا عنوانِ طولانی‌تر در نمودار جا شود.

اگر اکنون death_valley_highs_lows.py را اجرا کنید خواهید دید که تنها یک داده از دست رفته:

1
Missing data for 2018-02-18 00:00:00

چون خطا به درستی مدیریّت شده کد ما قادر است که نموداری تولید کند و از داده‌ی مفقود بگذرد. شکل ۱۶-۶ نمودار حاصل را نشان می‌دهد.

شکل ۱۶-۶- دماهای بیشینه و کمینه‌ی روزانه برای دره‌ی مرگ

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

بسیاری از مجموعه‌داده‌های مورد نظر شما شامل داده‌های مفقود، داده‌هایی که شکل درست ندارند یا داده‌های نادرست‌اند. شما می‌توانید به کمک ابزارهایی که در نیمه‌ی اوّل این کتاب آموختید این شرایط را مدیریّت کنیم. اینجا از بلوک try-except-else برای رسیدگی به داده‌ی مفقود استفاده کردیم. گاهی شما از continue برای پریدن از روی برخی داده‌ها یا از remove() یا del() برای حذف کردن برخی از داده‌های استخراج‌شده استفاده می‌کنید. هر رویکردی را که کار می‌کند پی بگیرید تا زمانی که نتیجه‌ی آن بصری‌سازی دقیق و معنادار باشد.