<jupyter_start><jupyter_text>如何對資料框進行基礎操作> 寫一些 pandas 語法操作 Johns Hopkins COVID-19 每日報告>> 標籤：程式設計，獲取載入，整併轉換郭耀仁<jupyter_code># 載入專案需要使用的套件
import datetime
import pandas as pd<jupyter_output><empty_output><jupyter_text>TL; DR在這個專案中，我們打算寫一些 pandas 語法操作約翰霍普金斯大學 COVID-19 Data Repository 中最新的每日報告，讀者將學會如何定義函式 `get_latest_daily_report()` 將約翰霍普金斯大學 COVID-19 Data Repository 中最新的每日報告載入成為資料框、如何衍生新的欄位（治療中案例數）、選擇特定欄位（挑出一個或多個）、篩選指定觀測值（台灣在哪裡）、分組摘要（以國家為單位聚合確診數）以及排序（將摘要結果由大到小遞減排序）。  資料來源資料來源是 [COVID-19 Data Repository by the Center for Systems Science and Engineering (CSSE) at Johns Hopkins University](https://github.com/CSSEGISandData/COVID-19) 中的每日報告資料夾 `/csse_covid_19_data/csse_covid_19_daily_reports`，該資料夾從 2020-01-22 開始每天都有一個單獨的 CSV 檔案記錄該日的全球現況。  載入最新的每日報告CSV 檔案的命名是以 `%m-%d-%Y` Unix 時間格式、俗稱的 `mm-dd-yyyy` 格式作為檔案名稱，如果希望載入最新的每日報告，我們可以用電腦的當天日期作為檔名，但是由於資料源更新時間、時區的差異，使用當天日期很有可能沒有對應的檔案，因此我們可以寫一段程式，他的處理邏輯是：1. 先以電腦的當天日期作為檔名是否可以載入成功2. 如果成功這段程式的任務就完成了3. 如果載入失敗產生錯誤訊息，就將當天日期減去 1，直到載入成功這段程式需要 Python 的標準套件 `datetime`、第三方套件 `pandas`、`try...except...` 語法以及 `while` 語法。其中 `datetime` 可以協助我們獲得電腦的當天日期、進行日期的運算以及調整日期的文字格式。<jupyter_code>latest_date = datetime.date.today()
latest_date_fmt = latest_date.strftime('%m-%d-%Y')
print(latest_date_fmt)<jupyter_output>09-06-2020<jupyter_text>第三方套件 `pandas` 可以協助我們將 CSV 檔案讀入成為方便摘要分析的 `DataFrame`，每日報告由於更新時間、時區差異的緣故，大概都會是昨天或者前天，因此如果貿然將當天日期作為檔名通常會獲得錯誤訊息。這時我們就可以利用 `try...except...` 將錯誤捕捉起來。<jupyter_code>csv_url = "https://raw.githubusercontent.com/CSSEGISandData/COVID-19/master/csse_covid_19_data/csse_covid_19_daily_reports/{}.csv".format(latest_date_fmt)
try:
    daily_report = pd.read_csv(csv_url)
except:
    print("尚未有 {} 的每日報告。".format(latest_date_fmt))<jupyter_output>尚未有 09-06-2020 的每日報告。<jupyter_text>最後加入 `while` 語法，目的是只要錯誤被捕捉起來，就將當天日期減 1 成為再前一天日期，再嘗試一次載入，假若再有錯誤被捕捉，就持續減去 1 天，直到成功為止。<jupyter_code>latest_date = datetime.date.today()
day_delta = datetime.timedelta(days=1)
fmt = '%m-%d-%Y'
while True:
    try:
        latest_date_fmt = latest_date.strftime(fmt)
        csv_url = "https://raw.githubusercontent.com/CSSEGISandData/COVID-19/master/csse_covid_19_data/csse_covid_19_daily_reports/{}.csv".format(latest_date_fmt)
        daily_report = pd.read_csv(csv_url)
        print("載入了 {} 的每日報告。".format(latest_date_fmt))
        break
    except:
        latest_date_fmt = latest_date.strftime(fmt)
        print("尚未有 {} 的每日報告。".format(latest_date_fmt))
        latest_date -= day_delta<jupyter_output>尚未有 09-06-2020 的每日報告。
載入了 09-05-2020 的每日報告。<jupyter_text>將載入最新的每日報告包裝成函式將前面的程式包裝成函式，可以回傳最新每日報告以及檔案日期。<jupyter_code>def get_latest_daily_report():
    """
    This function returns the latest global daily report from https://github.com/CSSEGISandData/COVID-19 and its file date.
    """
    latest_date = datetime.date.today()
    day_delta = datetime.timedelta(days=1)
    fmt = '%m-%d-%Y'
    while True:
        try:
            latest_date_fmt = latest_date.strftime(fmt)
            csv_url = "https://raw.githubusercontent.com/CSSEGISandData/COVID-19/master/csse_covid_19_data/csse_covid_19_daily_reports/{}.csv".format(latest_date_fmt)
            daily_report = pd.read_csv(csv_url)
            print("載入了 {} 的每日報告。".format(latest_date_fmt))
            break
        except:
            latest_date_fmt = latest_date.strftime(fmt)
            print("尚未有 {} 的每日報告。".format(latest_date_fmt))
            latest_date -= day_delta
    return latest_date, daily_report
latest_date, daily_report = get_latest_daily_report()
daily_report.shape # 每日報告的外觀
daily_report.head() # 每日報告的前五列<jupyter_output><empty_output><jupyter_text>衍生新的欄位治療中案例數可以用既有的欄位計算而得，常見的定義為：確診數減去死亡數再減痊癒數。\begin{equation}\text{Active} = \text{Confirmed} - \text{Deaths} - \text{Recovered}\end{equation}<jupyter_code>active = daily_report["Confirmed"] - daily_report["Deaths"] - daily_report["Recovered"]
active<jupyter_output><empty_output><jupyter_text>與原本資料框中的欄位 Active 比對可以檢查每日報告中有問題的觀測值紀錄。<jupyter_code>print((active != daily_report["Active"]).sum()) # 衍生欄位與原有欄位 Active 不同的觀測值數有幾筆
daily_report[active != daily_report["Active"]]  # 問題的觀測值紀錄<jupyter_output>4<jupyter_text>在資料框的第 0 欄插入衍生欄位。<jupyter_code>daily_report.insert(0, 'Derived_Active', active)
daily_report.head()<jupyter_output><empty_output><jupyter_text>選擇特定欄位在中括號裡頭輸入欄位名稱可以將資料以 `Series` 外型從資料框中取出。<jupyter_code>daily_report["Country_Region"]<jupyter_output><empty_output><jupyter_text>若想要選擇多個欄位，將多個欄位名稱以 `list` 傳入中括號。<jupyter_code>multiple_columns = ["Country_Region", "Confirmed", "Deaths", "Recovered"]
daily_report[multiple_columns]<jupyter_output><empty_output><jupyter_text>篩選指定觀測值在中括號裡頭輸入判斷條件所獲得的布林值 `Series` 可以獲得指定的觀測值。<jupyter_code>is_tw = daily_report['Country_Region'] == 'Taiwan*' # 台灣在哪裡
is_tw
daily_report[is_tw] # is_tw 是一個布林值 Series<jupyter_output><empty_output><jupyter_text>分組摘要以國家為單位，所以在 `groupby()` 方法中傳入 Country_Region 欄位，獲得一個 `DataFrameGroupBy` 類別。<jupyter_code>daily_report.groupby("Country_Region")<jupyter_output><empty_output><jupyter_text>指定 `DataFrameGroupBy` 類別的欄位與聚合函式，獲得分組摘要的結果，是一個 `Series`。<jupyter_code>daily_report.groupby("Country_Region")['Confirmed'].sum()<jupyter_output><empty_output><jupyter_text>排序呼叫 `Series` 的 `sort_values(ascending=False)` 方法將摘要結果由大到小遞減排序。<jupyter_code>confirmed_by_country = daily_report.groupby("Country_Region")['Confirmed'].sum()
confirmed_by_country.sort_values(ascending=False)[:10] # 顯示確診人數前 10 高的國家<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.12316005217067263, 'fraction_numerical': 0.016582820942798584, 'mean_word_length': 7.309597523219814, 'pattern_counts': {'":': 0, '<': 53, '<?xml version=': 0, '>': 56, 'https://': 5, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '14', 'dir': 'jupyter-structured-clean-dedup', 'id': '307484', 'license': 'MIT', 'n_tokens_mistral': 2996, 'n_tokens_neox': 3176, 'n_words': 235, 'path': 'project-pd-basic-manipulations.ipynb', 'repo_name': 'datainpoint/project-pd-basic-manipulations', 'size': '5367'}