הסברים הדרכתיים

איך לייצר מפות חום באמצעות פייתון

By נובמבר 9, 2017 No Comments

בחודש אוקטובר 2017 בערך, פורסמה מפת חום של הסימפסונים תחת הכותרת של 'בואו לראות מתי הסימפסונים נהיו פחות טובים' או משהו כזה וכשראיתי את זה, חשבתי לעצמי שזה יכול להיות נחמד לכתוב את הקוד בעצמי – הפוסט הזה יתאר את כל מה שעשיתי, שלב אחרי שלב, ברמה הפרקטית.

עוד פוסטים שהגיעו למפות החום:

  1. קרב הסדרות הגדול
  2. סדרות פוליטיות
  3. סדרות מבוססות קומיקס

כיוון שלא הכל ממש מעניין פה, מי שירצה את הקוד הסופי מוזמן לקחת אותו מהגיטהאב שלי

שלב ראשון – איך המידע בנוי בכלל?

בפוסט הראשון של קרב הסדרות הגדול, כתבתי למה דווקא בחרתי להישען על מידע מ-IMDB, פה אנחנו נתעסק במה קרה אחרי שהחלטנו כבר מאיפה לשאוב את המידע.

אז דבר ראשון השאלה היא – מה הדבר הכי טוב שאנחנו נרצה שיקרה?

אנחנו נרצה מאגר מסודר, יפה ונקי שמתאר עבור כל פרק מה הציון שלו, אחרי שיטוט קצר, אנחנו נגיע למבנה הזה:

מבנה הנתונים ב-IMDB עבור הסדרה ארצ'ר

מבנה הנתונים ב-IMDB עבור סדרות

ניתן לראות שמספר פרק מיוצג כאן על ידי שילוב נתונים של מספר העונה ומספר הפרק בתצורה הזאת: {{season number}}.{{episode number}} – אנחנו צריכים לזכור את זה, כי יש לזה משמעות, אם אנחנו רוצים לפצל את הנתונים האלו.

(הערה – בכל פעם שאני אשתמש בסימון {{ }} – אני מתכוון למשתנה)

אנחנו רואים שיש לנו כאן צורה מסודרת יחסית שיושבת תחת הקישור:

http://www.imdb.com/title/{{Code-Series}}/epdate

נזכור את הכתובת הזאת לאחר כך.

שלב שני – ייבוא החבילות הרלוונטיות

התחלתי בייבוא החבילות שנראו לי רלוונטיות:

python - importing packages - IMDB Heatmaps

ייבוא חבילות – אפשר לייבא גם antigravity

Pandas בשביל לשאוב את הנתונים מהדף הרלוונטי.

seaborn ו-pyplot בשביל להציג את המידע, כשאני יודע מראש שאני מתכוון להשתמש ב-sns.heatmap בשביל לייצר מפות חום (הגיוני, סה"כ).

 

שלב שלישי – קריאת וסידור הנתונים

לפנדות יש את מתודת קריאת ה-HTML, זה בדיוק מה שאנחנו צריכים – מה היא עושה?

היא מזהה אלמנטי טבלאות (<tr>), ואז שומרת בזיכרון את כל האלמנט על שלל השורות (<td>) של האלמנט.

מה קורה אם יש יותר מטבלה אחת בעמוד?

הפקודה שומרת כאלמנט על את כל הטבלאות תחת רשימה.

נציין לקוד שאנחנו רוצים את הקידוד תחת utf-8, ששורת הכותרת קיימת (מצויינת כ-0) ועכשיו נסתכל על עמודת converters.

python - read HTML with Pandas - IMDB Heatmaps

שאיבת הטבלה מדף האינטרנט

כשהתחלתי עם הקוד הזה, רצתי לבדוק סדרות שאני אוהב בשביל לראות אם אחרים הרגישו כמוני, ואז הגעתי למשחקי הכס – ומה גיליתי?
שיש רק תשעה פרקים בכל עונה – האם זה הגיוני?
הרי אנחנו יודעים שיש עשרה פרקים (חוץ מבאחרונה) – ואז הבנתי שהבעיה היא שפנדות קורא את המידע עבור פרק 1.1 בדיוק כמו פרק 1.10, כיון שהוא חושב שאלו floats.
למעשה הנתונים שאני רואה עבור הפרקים הראשונים (1.1) הם ממוצע הפרקים 10 ו-1.

היינו צריכים, אם כך, להגדיר לפייתון מה סוג המידע עבור כל עמודה – וזה בדיוק מה שעשינו –

  • רצינו שמספר הפרק יהיה מיוצג כמחרוזת – כדי שלא יהיה לנו חיבור\ממוצע של נתונים
  • רצינו שמספר הפרק גם יהיה מחרוזת, כדי שנוכל להפריד בצורה הכי פשוטה את מספרי העונות למספרי הפרקים.
  • הרייטינג הניתן לכל פרק כמספר עם נקודה עשרונית, כדי שנוכל להגיע לדיוק הוגן עבור הנתונים.
  • כמות מצביעים – כמספר שלם – כי אין חצי מצביע.

כמו שציינתי למעלה, כשפנדות קורא HTML ויש יותר מטבלה אחת, הוא שומר את כל האובייקטים תחת רשימה\מערך (תלוי בשפה שלכם), אז אנחנו נגדיר בדיוק איך אנחנו רוצים שהמסד שלנו יראה –

 

python - Select the correct table - IMDB Heatmaps

בחירת הטבלה הנכונה מבין רשימת הטבלאות

אוקיי, עכשיו אנחנו נבנה שתי עמודות חדשות, למה?

כיוון שהעונות והפרקים מסודרים בתצורה של מחרוזת (כדי שנוכל לעבד את המספרים), ואנחנו נרצה להחזיר אותם להיות מספרים (כדי שיהיה לנו סידור בסוף התהליך), אנחנו נצטרך למעשה להפריד בין המספרים על ידי ההפרדה של "." – ממש כמו שעשינו בפוסט הקצר על {{איך לפצל טקסט לעמודות באקסל}}.

python - Arranging columns with apply and Lambda - IMDB Heatmaps

שילוב של lambda ו-apply כמנוע צמיחה בקוד פנדות

יופי, אז כרגע מסד הנתונים שלנו נראה ככה:

python - DataBase Head - IMDB Heatmaps

מבלי לגגל – איזו סדרה מוצגת כאן?

בואו נתחיל לעבוד על הגרף עצמו –

הדברים שרציתי שיהיו בגרף (בשביל לתת אמדן למהימנות הנתונים) – מה היא כמות המצביעים (סך הכל מצביעים), מה הציון המינימלי, מה הציון המקסימלי ומה הציון הממוצע – כי לפעמים סטטיסטיקה יכולה לשקר.

הדבר הלא מאוד אלגנטי הזה עושה את זה:

python - Arraging data for graph - IMDB Heatmaps

ניקח את המינימום, מקסימום, כמות מצביעים וממוצע הצבעות

כשאני אומר 'עושה' אני מתכוון כמובן למכין, הצגת הנתונים על הגרף עצמו תגיע מאוחר יותר.

עכשיו הגיע הזמן לייצר את טבלת הציר, שממנה נגזור את מפת החום (הערה מעניינת – אפשר לייצר מפות חום גם מבלי להכין את טבלת הציר מבעוד מועד, אבל זה סתם יוצא קצת יותר מסובך וקצת יותר תקוע).

נראה לי שאין יותר מדי מה להרחיב על החלק הזה – הוא מאוד ישיר (ובכנות? הרבה יותר נוח מטבלת ציר של אקסל):

python - Pandas Pivot Table - IMDB Heatmaps

טבלת ציר בפייתון

שלב רביעי – WET או DRY?

אז התחלתי לייצר את מפות החום, והכל היה מגניב ונפלא, אבל בשביל להכניס את שם הטבלה, הייתי צריך ממש להקליד את זה כל פעם מחדש, מה שמוביל אותנו לעקרון הרטוב\יבש.

WET או DRY (או אולי זה גם וגם) – הם שני ביטויים חשובים בעולם שבו יש אלגוריתמים – אלו הם ראשי תיבות של:

WET – We Enjoy Typing

DRY – Don’t Repeat Yourself

השילוב הזה נועד להזכיר לנו שאם שאין סיבה לעשות מטלה מסויימת יותר משלוש פעמים בצורה ידנית – ושכנראה שאפשר להפוך אותה לאוטומטית – וזה מה שנעשה עכשיו:

python - requests and BeautifulSoup - IMDB Heatmaps

HTTP for Humans

הקוד הזה ניגש לדף ה-HTML, מוצא את התוכן ומוציא מתוכו את הכותרת, מכיוון שהמבנה של הדפים ב-IMDB הוא קבוע, אנחנו יכולים להניח ברמת וודאות יחסית גבוהה שהקוד יחזיר לנו את הכותרת שאנחנו רוצים.

מכיוון שבשלב הזה כבר יש לי את מפות החום עבור כל הפוסטים – אני יכול להגיד שזה לא פספס פעם אחת -אבל שלא ציפיתי ממנו שיפספס, כי בדרך כלל HTML באתרים גדולים הוא פשוט תבנית שלתוכה מזריקים מידע ממאגר המידע.

 

שלב חמישי – בניית הגרף עצמו

 

אלמנט הגרף נראה ככה:

python -graph object - IMDB Heatmaps

פתיחת אובייקט גרף וצירים

למה אנחנו עושים את זה דרך subplots ולא ישר דרך heatmap?

כיוון שאם לא היינו עושים את זה – היינו מקבלים צירים הפוכים (בערך – קחו את הקוד המלא ותשנו את האלמנט רק למפת חום)

python - pyplot show heatmap- IMDB Heatmaps

הצגת המידע כולל התאמות שנרצה שתהיינה בגרף

כמו שאמרתי, הקוד נמצא גם בגיטהאב שלי, מי שרוצה להשתמש בו – מוזמן.

 

זהו, נגמר הפוסט, התהליך הזה של כתיבת קוד, אצלי לפחות מתחיל מתכנון מרכזי של מה אני רוצה לעשות (דף ועט כמו פרימיטיבי), כתיבת ה'מנוע העיקרי' ואז מתחיל לתקן ולהוסיף דברים שנראים לי רצויים.

פייתון למדתי באופן עצמאי, לכן ברור לי שיכול להיות שעשיתי בקוד דברים שהם פחות יעילים ממה שמפתח מלומד היה עושה – אז אם יש לכם הארות – אני אשמח לשמוע!

מקווה שנהניתם מהפוסט הזה!

 

 

 

Leave a Reply