Pandas

Table of Contents

Hits

1. 簡介

1.1. Pandas

  • 建構於 NumPy 之上分析模組,適合處理表格資料或異質資料。
  • 於 2009 年底開源出來,提供高效能、簡易使用的資料格式(Data Frame,為 R 語言主要資料格式),可以讓使用者可以快速操作及分析資料。
  • Pandas 強化了資料處理的方便性也能與處理網頁資料與資料庫資料等,有點類似於Office 的 Excel,能更加方便的進行運算、分析等1
  • Pandas 主要特色有2
    1. 在異質數據的讀取、轉換和處理上,都讓分析人員更容易處理,例如:從列欄試算表中找到想要的值。
    2. Pandas 提供兩種主要的資料結構,Series 與 DataFrame。Series 顧名思義就是用來處理時間序列相關的資料(如感測器資料等),主要為建立索引的一維陣列。DataFrame 則是用來處理結構化(Table like)的資料,有列索引與欄標籤的二維資料集,例如關聯式資料庫、CSV 等等。
    3. 透過載入至 Pandas 的資料結構物件後,可以透過結構化物件所提供的方法,來快速地進行資料的前處理,如資料補值,空值去除或取代等。
    4. 更多的輸入來源及輸出整合性,例如:可以從資料庫讀取資料進入 Dataframe,也可將處理完的資料存回資料庫。

1.1.1. CSV

  • Comma-Separated Values, 為純文字檔,以逗號分隔值,有時也稱為字元分隔值,因為分隔字元也可以不是逗號)。
  • 純文字意味著該檔案是一個字元序列,不含必須像二進位制數字那樣被解讀的資料。
  • CSV 檔案由任意數目的記錄組成,記錄間以某種換行符分隔;每條記錄由欄位組成,欄位間的分隔符是其它字元或字串,最常見的是逗號。

1.2. Pandas 資料結構

Pandas 兩類資料結構3, 2:

  1. Series: 用來處理時間序列相關的資料(如感測器資料等),主要為建立索引的一維陣列。
  2. DataFrame: 是一個二維標籤資料結構,可以具有不同類型的行(column),類似 Excel的資料表,對於有使用過統計軟體的分析人員應該不陌生。簡單來說,Series 可以想像為一行多列(row)的資料,而 DataFrame 是多行多列的資料,藉由選擇索引(列標籤)和行(行標籤)的參數來操作資料,就像使用統計軟體透過樣本編號或變項名稱來操作資料。

Series與DataFrame的差異可由圖1看出4:

2024-09-15_17-09-32_dataframe_series-e1711596564546.png

Figure 1: Series v.s. Dataframe

2. Series

一維資料(表格中的一欄),類似numpy中的vector,但可以儲存任何類型的數據,包括整數、浮點數、字串等等。

2.1. 建立: 資料類型可為 array, dictionary

2.1.1. 由 array 建立 Series

1: import pandas as pd
2: 
3: cars = ["SAAB", "Audi", "BMW", "BENZ", "Toyota", "Nissan", "Lexus"]
4: print("資料型別:", type(cars))
5: carsToSeries = pd.Series(cars)
6: print("資料型別:", type(carsToSeries))
7: print(carsToSeries.shape)
8: print(carsToSeries)
9: print("carsToSeries[1]: ", carsToSeries[1])
資料型別: <class 'list'>
資料型別: <class 'pandas.core.series.Series'>
(7,)
0      SAAB
1      Audi
2       BMW
3      BENZ
4    Toyota
5    Nissan
6     Lexus
dtype: object
Audi

2.2. 資料篩選

2.2.1. 由dict來建立pandas.Series()

就是把dict的key當成index

 1: import pandas as pd
 2: 
 3: dict = {
 4:     "city": "Kaohsiung",
 5:     "speedCamera1": "13213",
 6:     "speedCamera2": "3242",
 7:     "speedCamera3": "134343",
 8:     "speedCamera4": "4312",
 9:     "speedCamera5": "533"
10: }
11: 
12: dictToSeries = pd.Series(dict, index = dict.keys()) # 排序與原 dict 相同
13: print(dictToSeries[0])
14: print("=====")
15: print(dictToSeries['speedCamera1'])
16: print("=====")
17: print(dictToSeries[[0, 2, 4]])
18: print("=====")
19: print(dictToSeries[['city', 'speedCamera1', 'speedCamera3']])
20: print("=====")
21: print(dictToSeries[:2])
22: print("=====")
23: print(dictToSeries[4:])
24: # 查詢
25: print("====會發現有一個NaN=====")
26: search=['speedCamera1', 'speedCamera6']
27: print(pd.Series(dictToSeries, index=search))
Kaohsiung
=====
13213
=====
city            Kaohsiung
speedCamera2         3242
speedCamera4         4312
dtype: object
=====
city            Kaohsiung
speedCamera1        13213
speedCamera3       134343
dtype: object
=====
city            Kaohsiung
speedCamera1        13213
dtype: object
=====
speedCamera4    4312
speedCamera5     533
dtype: object
====會發現有一個NaN=====
speedCamera1    13213
speedCamera6      NaN
dtype: object

3. DataFrame

直觀的看DataFrame,這就是個Excel表格。

3.1. DataFrame 建立

可利用 Dictionary 或是 Array 來建立,並使用 DataFrame 的方法來操作資料查看、資料篩選、資料切片、資料排序等運算。

3.2. 由 Dictionary 建立

 1: import pandas as pd
 2: 
 3: hobby = ["Movies", "Sports", "Coding", "Fishing", "Dancing", "cooking"]
 4: count = [46, 8, 12, 12, 6, 58]
 5: 
 6: dict = {"hobby": hobby,
 7:         "count": count
 8:        }
 9: print(dict)
10: df = pd.DataFrame(dict)
11: print(df)
{'hobby': ['Movies', 'Sports', 'Coding', 'Fishing', 'Dancing', 'cooking'], 'count': [46, 8, 12, 12, 6, 58]}
     hobby  count
0   Movies     46
1   Sports      8
2   Coding     12
3  Fishing     12
4  Dancing      6
5  cooking     58

3.3. 由 Array 建立

1: import pandas as pd
2: 
3: ary = [["Movies", 46],["Sports", 8], ["Coding", 12], ["Fishing",12], ["Dancing",6], ["cooking",8]]
4: print(ary)
5: ary2df = pd.DataFrame(ary, columns = ["hobby", "count"]) # 單純的二維矩陣沒有欄位名稱,要外加指定欄標籤名稱
6: print(ary2df)
7: 
[['Movies', 46], ['Sports', 8], ['Coding', 12], ['Fishing', 12], ['Dancing', 6], ['cooking', 8]]
     hobby  count
0   Movies     46
1   Sports      8
2   Coding     12
3  Fishing     12
4  Dancing      6
5  cooking      8

3.4. 讀入外部資料檔來建立 Dataframe

3.4.1. 本機CSV(由本機端的PyCharm執行,不能在Google colab上跑)

  • 可以從異質資料來源讀取檔案(如 CSV 檔)內容,並將資料放入 DataFrame 中,進行資料查看、資料篩選、資料切片等運算。
  • 如果資料檔和程式放在同一目錄(資料夾)
  • 如果資料檔放在本機在其他地方
    • 絕對路徑
    • 相對路徑
  • 下載範例檔:scores.csv
1: import pandas as pd
2: 
3: # 讀取csv
4: df = pd.read_csv("/Users/student/Downloads/scores.csv") #這裡的路徑要自行更改
5: print("===全部資料===")
6: print(df)

3.4.2. Google Colab的檔案上傳

import google.colab後,使用files.upload() 就能夠產生上傳檔案,此時cell會進入等待狀態,選取你本機的檔案即可上傳。

1: from google.colab import files
2: uploaded = files.upload()

執行後會出現以下畫面:

2023-12-22_09-37-23_2023-12-22_09-36-51.png
點選「瀏覽」選取檔案後即可將檔案上傳至Colab

3.4.2.1. 檔案上傳到哪裡?

可以執行!ls查看現在所在的目錄(資料夾)的內容

1: !ls

也可以執行!pwd查看現在在哪一個目錄(資料夾)

1: !pwd
3.4.2.2. 在Google Colab以Pandas查看csv檔
1: import pandas as pd
2: 
3: # 讀取csv
4: df = pd.read_csv("/content/scores.csv") #這裡的路徑要自行更改
5: print("===全部資料===")
6: print(df)

3.4.3. 由Pandas直接讀取線上CSV檔

1: import pandas as pd
2: docURL = 'https://letranger.github.io/PythonCourse/scores.csv' #直接指定檔案的URL
3: df = pd.read_csv(docURL)
4: print('=====dataFrame的維度')
5: print(df.shape)
6: print('=====dataFrame的數值分佈概況')
7: print(df.describe())
8: print('=====dataFrame的前5筆記錄')
9: print(df.head(5))
=====dataFrame的維度
(212, 6)
=====dataFrame的數值分佈概況
       classparti     typing    homework     midexam   finalexam
count  212.000000  212.00000  212.000000  211.000000  212.000000
mean    92.386792   82.09434   89.394764   62.863033   49.458491
std     13.798874   23.06041   19.471763   34.104173   34.831187
min     14.000000    0.00000   10.750000    0.000000    0.000000
25%     87.000000   68.00000   83.880000   35.000000   20.000000
50%     94.000000   80.00000   97.370000   67.000000   45.000000
75%    101.000000   96.00000  102.630000   95.000000   76.000000
max    120.000000  120.00000  107.890000  113.500000  115.000000
=====dataFrame的前5筆記錄
           id  classparti  typing  homework  midexam  finalexam
0  S201910901         100      72     92.11     48.0       16.0
1  S201910902          96      56     93.42     60.0       40.0
2  S201910903          96      76    102.63     45.0       28.0
3  S201910904          93      64     86.84     44.0       25.0
4  S201910905          93      56     42.11      0.0       20.0

4. DataFrame 的資料瀏覽

4.1. 基本函數

  • shape
    用途:查看 DataFrame 的維度(行數與列數),傳回一個包含行數和列數的 tuple。
  • describe()
    提供數據的統計摘要, 對數值型資料列出統計資訊,如平均值、標準差、最小值、四分位數等。
  • head()
    顯示 DataFrame 的前幾行資料, 預設顯示前 5 行資料,但可以加入顯示行數參數。
  • tail()
    顯示 DataFrame 的後幾行資料, 預設顯示最後 5 行資料,和 head() 類似,可以指定顯示行數。
  • columns
    列出 DataFrame 的所有欄位名稱, 傳回所有列(欄)的名稱,幫助了解 DataFrame 的結構。
  • index
    返回 DataFrame 的索引(行標籤), 查看 DataFrame 中的行標籤,用於確認資料的索引範圍或類型。
  • info()
    顯示 DataFrame 的結構化資訊, 包含 DataFrame 中的行數、列數、欄位類型、非空值計數、記憶體使用情況等,常用於總覽資料集的結構。

4.1.1. 範例

 1: import pandas as pd
 2: docURL = 'https://letranger.github.io/PythonCourse/scores.csv'
 3: df = pd.read_csv(docURL)
 4: 
 5: print("====df.shape====")
 6: print(df.shape) # 回傳列數與欄數
 7: print("====df.describe()====")
 8: print(df.describe()) # 回傳描述性統計
 9: print("====df.head(3)====")
10: print(df.head(3)) # 回傳前三筆觀測值
11: print("====df.tail(3)====")
12: print(df.tail(3)) # 回傳後三筆觀測值
13: print("====df.columns====")
14: print(df.columns) # 回傳欄位名稱
15: print("====df.columns====")
16: print(df.index) # 回傳 index
17: print("====df.info====")
18: print(df.info) # 回傳資料內容
====df.shape====
(212, 6)
====df.describe()====
                 id  classparti     typing    homework     midexam   finalexam
count  2.120000e+02  212.000000  212.00000  212.000000  211.000000  212.000000
mean   2.019113e+08   92.386792   82.09434   89.394764   62.863033   49.458491
std    2.933047e+02   13.798874   23.06041   19.471763   34.104173   34.831187
min    2.019109e+08   14.000000    0.00000   10.750000    0.000000    0.000000
25%    2.019110e+08   87.000000   68.00000   83.880000   35.000000   20.000000
50%    2.019111e+08   94.000000   80.00000   97.370000   67.000000   45.000000
75%    2.019116e+08  101.000000   96.00000  102.630000   95.000000   76.000000
max    2.019117e+08  120.000000  120.00000  107.890000  113.500000  115.000000
====df.head(3)====
          id  classparti  typing  homework  midexam  finalexam
0  201910901         100      72     92.11     48.0       16.0
1  201910902          96      56     93.42     60.0       40.0
2  201910903          96      76    102.63     45.0       28.0
====df.tail(3)====
            id  classparti  typing  homework  midexam  finalexam
209  201911728          83      48    102.63     83.0       75.0
210  201911729          87      84    105.26    112.3      103.0
211  201911730          96      72    102.63     91.0      100.0
====df.columns====
Index(['id', 'classparti', 'typing', 'homework', 'midexam', 'finalexam'], dtype='object')
====df.columns====
RangeIndex(start=0, stop=212, step=1)
====df.info====
<bound method DataFrame.info of             id  classparti  typing  homework  midexam  finalexam
0    201910901         100      72     92.11     48.0       16.0
1    201910902          96      56     93.42     60.0       40.0
2    201910903          96      76    102.63     45.0       28.0
3    201910904          93      64     86.84     44.0       25.0
4    201910905          93      56     42.11      0.0       20.0
..         ...         ...     ...       ...      ...        ...
207  201911726         106      80    102.63     96.5      103.0
208  201911727          82      60    102.63     84.0      100.0
209  201911728          83      48    102.63     83.0       75.0
210  201911729          87      84    105.26    112.3      103.0
211  201911730          96      72    102.63     91.0      100.0

[212 rows x 6 columns]>

4.2. DataFrame 資料排序

  • sort_values(): 依欄位的值來排序(較常用)

    1: import pandas as pd
    2: docURL = 'https://letranger.github.io/PythonCourse/scores.csv'
    3: df = pd.read_csv(docURL)
    4: 
    5: print("====Original====")
    6: print(df.head())
    7: print("===.sort_values()====")
    8: print(df.sort_values(by = 'classparti')[:5])
    9: print(df.sort_values(by = ['midexam', 'finalexam'], ascending=False)[:5])
    
      ====Original====
                 id  classparti  typing  homework  midexam  finalexam
      0  S201910901         100      72     92.11     48.0       16.0
      1  S201910902          96      56     93.42     60.0       40.0
      2  S201910903          96      76    102.63     45.0       28.0
      3  S201910904          93      64     86.84     44.0       25.0
      4  S201910905          93      56     42.11      0.0       20.0
      ===.sort_values()====
                   id  classparti  typing  homework  midexam  finalexam
      18   S201910919          14      56     25.92      0.0        0.0
      42   S201911006          20      68     92.11     27.0       20.0
      27   S201910928          37     108     89.47      0.0       20.0
      116  S201911307          53      60     41.45      0.0        0.0
      10   S201910911          62      44     20.39      4.0        0.0
                   id  classparti  typing  homework  midexam  finalexam
      88   S201911115         120      88    105.26    113.5     111.00
      98   S201911125         119      80    107.89    113.2     115.00
      210  S201911729          87      84    105.26    112.3     103.00
      11   S201910912          87      92     92.11    110.8     103.75
      195  S201911714         102      44    107.89    110.0     110.00
    
  • sort_index(): 依欄位名稱或index值來排。The axis along which to sort. The value 0 identifies the rows, and 1 identifies the columns.

     1: import pandas as pd
     2: docURL = 'https://letranger.github.io/PythonCourse/scores.csv'
     3: df = pd.read_csv(docURL)
     4: 
     5: print("====Original====")
     6: print(df.head())
     7: print("===.sort_index()====")
     8: print(df.sort_index(axis = 1, ascending = True))
     9: print("===.sort_index()====")
    10: print(df.sort_index(axis = 0, ascending = False))
    
      ====Original====
                 id  classparti  typing  homework  midexam  finalexam
      0  S201910901         100      72     92.11     48.0       16.0
      1  S201910902          96      56     93.42     60.0       40.0
      2  S201910903          96      76    102.63     45.0       28.0
      3  S201910904          93      64     86.84     44.0       25.0
      4  S201910905          93      56     42.11      0.0       20.0
      ===.sort_index()====
           classparti  finalexam  homework          id  midexam  typing
      0           100       16.0     92.11  S201910901     48.0      72
      1            96       40.0     93.42  S201910902     60.0      56
      2            96       28.0    102.63  S201910903     45.0      76
      3            93       25.0     86.84  S201910904     44.0      64
      4            93       20.0     42.11  S201910905      0.0      56
      ..          ...        ...       ...         ...      ...     ...
      207         106      103.0    102.63  S201911726     96.5      80
      208          82      100.0    102.63  S201911727     84.0      60
      209          83       75.0    102.63  S201911728     83.0      48
      210          87      103.0    105.26  S201911729    112.3      84
      211          96      100.0    102.63  S201911730     91.0      72
    
      [212 rows x 6 columns]
      ===.sort_index()====
                   id  classparti  typing  homework  midexam  finalexam
      211  S201911730          96      72    102.63     91.0      100.0
      210  S201911729          87      84    105.26    112.3      103.0
      209  S201911728          83      48    102.63     83.0       75.0
      208  S201911727          82      60    102.63     84.0      100.0
      207  S201911726         106      80    102.63     96.5      103.0
      ..          ...         ...     ...       ...      ...        ...
      4    S201910905          93      56     42.11      0.0       20.0
      3    S201910904          93      64     86.84     44.0       25.0
      2    S201910903          96      76    102.63     45.0       28.0
      1    S201910902          96      56     93.42     60.0       40.0
      0    S201910901         100      72     92.11     48.0       16.0
    
      [212 rows x 6 columns]
    
  • sort 後的結果為 複本 ,不改變原本的資料

     1: import pandas as pd
     2: docURL = 'https://letranger.github.io/PythonCourse/scores.csv'
     3: df = pd.read_csv(docURL)
     4: 
     5: print("====Original====")
     6: print(df.head())
     7: print("===.sort_index()====")
     8: print(df.sort_index(axis = 1, ascending = True))
     9: 
    10: print('=== 在經過排序後,現在的df內容為 ===')
    11: print(df.head())
    
      ====Original====
                 id  classparti  typing  homework  midexam  finalexam
      0  S201910901         100      72     92.11     48.0       16.0
      1  S201910902          96      56     93.42     60.0       40.0
      2  S201910903          96      76    102.63     45.0       28.0
      3  S201910904          93      64     86.84     44.0       25.0
      4  S201910905          93      56     42.11      0.0       20.0
      ===.sort_index()====
           classparti  finalexam  homework          id  midexam  typing
      0           100       16.0     92.11  S201910901     48.0      72
      1            96       40.0     93.42  S201910902     60.0      56
      2            96       28.0    102.63  S201910903     45.0      76
      3            93       25.0     86.84  S201910904     44.0      64
      4            93       20.0     42.11  S201910905      0.0      56
      ..          ...        ...       ...         ...      ...     ...
      207         106      103.0    102.63  S201911726     96.5      80
      208          82      100.0    102.63  S201911727     84.0      60
      209          83       75.0    102.63  S201911728     83.0      48
      210          87      103.0    105.26  S201911729    112.3      84
      211          96      100.0    102.63  S201911730     91.0      72
    
      [212 rows x 6 columns]
      === 在經過排序後,現在的df內容為 ===
                 id  classparti  typing  homework  midexam  finalexam
      0  S201910901         100      72     92.11     48.0       16.0
      1  S201910902          96      56     93.42     60.0       40.0
      2  S201910903          96      76    102.63     45.0       28.0
      3  S201910904          93      64     86.84     44.0       25.0
      4  S201910905          93      56     42.11      0.0       20.0
    

4.3. DataFrame 處理遺漏值

4.3.1. 觀察遺失狀況

  • isnull(): 用來檢查 DataFrame 中的遺漏值,並傳回一個布林值的 DataFrame,True 表示該值為 NaN,False 表示該值不是 NaN。
  • notnull(): 傳回一個與原資料相同大小的布林值 DataFrame,其中 True 表示資料為 NaN。
  • any(): 一個常用於處理布林值資料的函數,它用來檢查在一個特定的軸(列或行)上,是否有 任何一個值 為 True。這在處理遺漏值時特別有用,因為你可以用它來檢查一個 DataFrame 的每一行或每一列中是否存在至少一個 True 值(例如:NaN 值)。
 1: import pandas as pd
 2: docURL = 'https://letranger.github.io/PythonCourse/scores-null.csv'
 3: df = pd.read_csv(docURL)
 4: 
 5: print("====原始資料====")
 6: print(df)
 7: # 查詢遺失值狀況
 8: print('====遺失值====')
 9: print(df.isnull())
10: print(df.isnull().sum())
====原始資料====
          id  classparti  typing  homework  finalExam
0  201910901       100.0    72.0     92.11       48.0
1  201910902        96.0    56.0     93.42       60.0
2  201910903        96.0    76.0    102.63        NaN
3  201910904         NaN    64.0     86.84       44.0
4  201910905        93.0    56.0     42.11        0.0
5  201910906       101.0   108.0    100.00        NaN
6  201910907       101.0     NaN     92.11       55.0
7  201910908        94.0    68.0    105.26       61.0
8  201910909         NaN    64.0     44.74       20.0
9  201910910        93.0   120.0     97.37       16.0
====遺失值====
      id  classparti  typing  homework  finalExam
0  False       False   False     False      False
1  False       False   False     False      False
2  False       False   False     False       True
3  False        True   False     False      False
4  False       False   False     False      False
5  False       False   False     False       True
6  False       False    True     False      False
7  False       False   False     False      False
8  False        True   False     False      False
9  False       False   False     False      False
id            0
classparti    2
typing        1
homework      0
finalExam     2
dtype: int64

4.3.2. dropna()

dropna() 用於刪除 DataFrame 中包含遺失值的行或列。

DataFrame.dropna(axis=0, how='any', thresh=None, subset=None, inplace=False)
  • axis: 指定刪除的方向。axis=0 刪除包含遺失值的行,axis=1 刪除包含遺失值的列,預設為 0(行)。
  • how: 確定是否刪除的條件。how=’any’ 表示只要行或列中有一個 NaN 就刪除,how=’all’ 表示必須全部是 NaN 才刪除,預設為 ’any’。
  • thresh: 保留至少有 thresh 個非 NaN 的行或列。
  • subset: 只在特定列中尋找遺失值。
  • inplace: 是否在原 DataFrame 中直接修改,True 表示在原地修改,False 則返回一個新的 DataFrame。
 1: import pandas as pd
 2: docURL = 'https://letranger.github.io/PythonCourse/scores-null.csv'
 3: df = pd.read_csv(docURL)
 4: print("====原始資料====")
 5: print(df.shape)
 6: print("====刪除有遺失值的記錄====")
 7: df0 = df.dropna()
 8: print(df0.shape)
 9: print(df.shape) #原來的df不受影響
10: df.dropna(inplace=True)
11: print(df.shape) #原來的df被改掉了QQ
====原始資料====
(10, 5)
(5, 5)
(10, 5)
(5, 5)

4.3.3. fillna()

DataFrame.fillna(value=None, method=None, axis=None, inplace=False, limit=None)
  • value: 用來填補遺失值的值,這個值可以是單個標量或字典來指定每列不同的填補值。
  • method: 填補方法,例如 ffill 代表用前一個有效值填補,bfill 代表用後一個有效值填補。
  • axis: 指定填補的方向,axis=0 填補行,axis=1 填補列,預設為 0(行)。
  • inplace: 是否直接修改原 DataFrame,預設為 False。
  • limit: 限制每一行或每一列最多填補幾個遺失值。
 1: import pandas as pd
 2: docURL = 'https://letranger.github.io/PythonCourse/scores-null.csv'
 3: df = pd.read_csv(docURL)
 4: 
 5: print("====原始資料====")
 6: print(df)
 7: 
 8: fill0 = df.fillna(0)
 9: print("====遺失值填零====")
10: print(fill0)
11: fillv = df.fillna({"classparti":999, "typing":0, "finalExam":"NULL"})
12: print("====遺失值填特定值====")
13: print(fillv)
====原始資料====
          id  classparti  typing  homework  finalExam
0  201910901       100.0    72.0     92.11       48.0
1  201910902        96.0    56.0     93.42       60.0
2  201910903        96.0    76.0    102.63        NaN
3  201910904         NaN    64.0     86.84       44.0
4  201910905        93.0    56.0     42.11        0.0
5  201910906       101.0   108.0    100.00        NaN
6  201910907       101.0     NaN     92.11       55.0
7  201910908        94.0    68.0    105.26       61.0
8  201910909         NaN    64.0     44.74       20.0
9  201910910        93.0   120.0     97.37       16.0
====遺失值填零====
          id  classparti  typing  homework  finalExam
0  201910901       100.0    72.0     92.11       48.0
1  201910902        96.0    56.0     93.42       60.0
2  201910903        96.0    76.0    102.63        0.0
3  201910904         0.0    64.0     86.84       44.0
4  201910905        93.0    56.0     42.11        0.0
5  201910906       101.0   108.0    100.00        0.0
6  201910907       101.0     0.0     92.11       55.0
7  201910908        94.0    68.0    105.26       61.0
8  201910909         0.0    64.0     44.74       20.0
9  201910910        93.0   120.0     97.37       16.0
====遺失值填特定值====
          id  classparti  typing  homework finalExam
0  201910901       100.0    72.0     92.11      48.0
1  201910902        96.0    56.0     93.42      60.0
2  201910903        96.0    76.0    102.63      NULL
3  201910904       999.0    64.0     86.84      44.0
4  201910905        93.0    56.0     42.11       0.0
5  201910906       101.0   108.0    100.00      NULL
6  201910907       101.0     0.0     92.11      55.0
7  201910908        94.0    68.0    105.26      61.0
8  201910909       999.0    64.0     44.74      20.0
9  201910910        93.0   120.0     97.37      16.0

4.4. [課堂練習]   TNFSH

以下列程式碼讀取線上資料檔,然後完成下列任務

  1. print出原始資料,觀察數據中是否有遺漏值。
  2. 使用 isnull() 和 notnull() 來檢查 DataFrame 中的遺漏值。顯示哪些欄位包含遺漏值。
  3. 列出成績不完整(有缺失值)的學生姓名
  4. 使用 dropna() 刪除包含遺漏值的學生記錄,並顯示刪除後的結果。
  5. 使用 fillna() 將遺漏值填充為平均值或其他特定值。依續以下列幾種填充方式:
    1. 科學、地理兩科缺考者一律給60分。
    2. 使用 0 填充其他所有遺漏值。

4.4.1. 參考

1: import pandas as pd
2: docURL = 'https://letranger.github.io/PythonCourse/prac_scores.csv'
3: df = pd.read_csv(docURL)
4: print(df.head())
     數學    英文    科學    歷史    地理   姓名
0   NaN  76.0  84.0  96.0  56.0  學生1
1  78.0   NaN  63.0  73.0  58.0  學生2
2  64.0  77.0  66.0  75.0  57.0  學生3
3  92.0   NaN  85.0  74.0  61.0  學生4
4  57.0  64.0  99.0  94.0  83.0  學生5

5. Dataframe 的選取與過濾

5.1. 資料選取: Select column(s)

  1. 使用 df[’column_name’] 來選取單個欄位
    這種方式傳回的是一個 Series,適用於只選取一個欄位的情況。這種方法最為直觀,當你知道欄位名稱時,直接使用 df[’column_name’] 即可。
  2. 使用 df[['col1', 'col2']] 選取多個欄位
    如果需要一次選取多個欄位,可以將多個欄位名稱放入一個列表中,再傳入 DataFrame 中。這樣做會傳回一個新的 DataFrame,並且可以進行進一步操作,例如使用 head() 來查看前幾行的數據。
  3. 使用 df.column_name 的簡寫方式
    這是一種更簡潔的語法,它只適用於列名為有效的 Python 識別符時(例如,列名中沒有空格或特殊字符)。通過 df.column_name 來選取欄位和 df[’column_name’] 效果相同,傳回一個 Series。

5.1.1. 範例

 1: import pandas as pd
 2: docURL = 'https://letranger.github.io/PythonCourse/scores.csv'
 3: df = pd.read_csv(docURL)
 4: 
 5: print(df.head(3))
 6: # 以 df.column name來選欄位
 7: print('=== df.id ===')
 8: print(df.id)
 9: # 以 df[['column']]  來選欄位
10: print("=== df[['id']] ===")
11: print(df[['id']])
12: # df[['id', 'typing']]的結果仍是dataframe,後面可以再加上dataframe的function
13: print(df[['id', 'typing']].head(3))
14: # 以 df.column 來選欄位
15: print(df.id, df.homework)
           id  classparti  typing  homework  midexam  finalexam
0  S201910901         100      72     92.11     48.0       16.0
1  S201910902          96      56     93.42     60.0       40.0
2  S201910903          96      76    102.63     45.0       28.0
=== df.id ===
0      S201910901
1      S201910902
2      S201910903
3      S201910904
4      S201910905
          ...
207    S201911726
208    S201911727
209    S201911728
210    S201911729
211    S201911730
Name: id, Length: 212, dtype: object
=== df[['id']] ===
             id
0    S201910901
1    S201910902
2    S201910903
3    S201910904
4    S201910905
..          ...
207  S201911726
208  S201911727
209  S201911728
210  S201911729
211  S201911730

[212 rows x 1 columns]
           id  typing
0  S201910901      72
1  S201910902      56
2  S201910903      76
0      S201910901
1      S201910902
2      S201910903
3      S201910904
4      S201910905
          ...
207    S201911726
208    S201911727
209    S201911728
210    S201911729
211    S201911730
Name: id, Length: 212, dtype: object 0       92.11
1       93.42
2      102.63
3       86.84
4       42.11
        ...
207    102.63
208    102.63
209    102.63
210    105.26
211    102.63
Name: homework, Length: 212, dtype: float64

5.2. 資料選取: Select using index (row)

在資料處理與分析中,Pandas 提供了方便的方法來根據列索引或條件選取 DataFrame 中的資料列。這讓使用者能夠靈活地篩選與操作資料,進行更精細的分析。

  1. 使用索引範圍選取資料列
    Pandas 支援使用索引範圍來選取 DataFrame 的資料列。類似於 Python 的切片語法:
    • df[start:end] : 選取第 start 到 end 行的資料。這種方法非常直觀,用於選取連續的一組資料列。
  2. 使用條件選取資料列
    除了直接選取特定的資料列,Pandas 也允許使用條件來篩選資料:
    • df[condition] :可以選取符合條件的資料。例如,篩選出作業成績小於 30 的學生記錄。
    • 可以用df.column_name來表示條件
  3. 合併列索引與欄位條件
    我們還可以結合列索引與欄位條件來選取資料。例如,使用條件選取特定列後,再篩選出符合條件的資料列,進行進一步操作。

5.2.1. 範例

 1: import pandas as pd
 2: docURL = 'https://letranger.github.io/PythonCourse/scores.csv'
 3: df = pd.read_csv(docURL)
 4: 
 5: # 以row index來選取資料
 6: print(df[1:3])
 7: # 以colu
 8: # 以條件來選取資料
 9: print(df[df.homework<30])
10: # 合併row and column兩項條件
11: print(df.id[df.homework<30])
12: print(df[['id', 'homework']][1:3])
          id  classparti  typing  homework  midexam  finalexam
1  201910902          96      56     93.42     60.0       40.0
2  201910903          96      76    102.63     45.0       28.0
            id  classparti  typing  homework  midexam  finalexam
10   201910911          62      44     20.39      4.0        0.0
18   201910919          14      56     25.92      0.0        0.0
23   201910924          75      48     10.75      0.0        0.0
124  201911315          71     120     15.35      0.0        0.0
140  201911331          93     120     25.88      0.0       16.0
10     201910911
18     201910919
23     201910924
124    201911315
140    201911331
Name: id, dtype: int64
          id  homework
1  201910902     93.42
2  201910903    102.63

5.3. 條件式選取資料

  1. 單一條件篩選
    需要根據單一條件篩選資料時:
    • df[condition]: 傳回一個新的 DataFrame,包含所有符合條件的資料列。
  2. 多條件篩選
    如果你需要根據多個條件來篩選資料,可以使用邏輯運算符來結合條件:
    • df[(condition)]
    • df[(condition 1) & (condition 2) ]
    • 使用多個條件時,必須 將每個條件放在括號內 ,這樣才能正確解析每個條件的優先級。

5.3.1. 範例

1: import pandas as pd
2: 
3: docURL = 'https://letranger.github.io/PythonCourse/scores.csv'
4: df = pd.read_csv(docURL)
5: 
6: print(df[(df.midexam >= 100) & (df.finalexam >= 100)])
             id  classparti  typing  homework  midexam  finalexam
11   S201910912          87      92     92.11    110.8     103.75
70   S201911034         104      92    102.63    100.8     101.00
88   S201911115         120      88    105.26    113.5     111.00
98   S201911125         119      80    107.89    113.2     115.00
102  S201911129         106      52    102.63    103.6     100.00
127  S201911318         108      80    102.63    104.8     100.00
138  S201911329         105      48    107.89    100.0     100.00
143  S201911334         100     120     81.58    104.8     113.00
153  S201911608          88       0    102.63    100.0     100.00
169  S201911624          82     100    102.63    101.5     105.00
182  S201911701         103     108     92.63    100.0     100.00
189  S201911708         106     108    102.63    107.2     101.00
190  S201911709         108      88    107.89    104.8     105.00
191  S201911710         102     100    102.63    100.0     105.00
193  S201911712         105      96    101.58    107.5     100.00
195  S201911714         102      44    107.89    110.0     110.00
196  S201911715         106     120    107.89    102.4     105.00
198  S201911717          80     120    107.89    106.0     100.00
201  S201911721         109      76    100.00    100.0     100.00
203  S201911722         105     120    102.63    101.5     105.00
210  S201911729          87      84    105.26    112.3     103.00

5.4. 進階條件過濾[loc/iloc]

在 Pandas 中,除了基本的索引與條件篩選,loc 和 iloc 提供了更加靈活且強大的資料篩選功能。這些方法允許我們根據行標籤、列標籤,或者純粹基於數值索引來選取資料。此外,between 方法則可以用來方便地篩選特定區間內的數值。

5.4.1. loc, iloc, between 5

5.4.1.1. loc
  • 用法:df.loc[row_label, column_label]
  • 這種方式是基於標籤(label)的選取,適合用於對特定行列進行精準選取。基於行標籤和列標籤(x_label、y_label)進行索引,以 column 名做為 index
 1: import pandas as pd
 2: 
 3: # 從遠端讀取 CSV 檔案
 4: docURL = 'https://letranger.github.io/PythonCourse/scores.csv'
 5: df = pd.read_csv(docURL)
 6: 
 7: # 查看前3行資料
 8: print(df.head(3))
 9: print("========")
10: 
11: # 使用 loc 選取 'homework' 小於 25 的資料,並只顯示 'id' 和 'homework' 兩個欄位
12: print(df.loc[df.homework < 25, ['id', 'homework']])
13: print("========")
14: 
15: # 使用 loc 選取第 2 行的 'homework' 欄位數值
16: print(df.loc[2, 'homework'])
           id  classparti  typing  homework  midexam  finalexam
0  S201910901         100      72     92.11     48.0       16.0
1  S201910902          96      56     93.42     60.0       40.0
2  S201910903          96      76    102.63     45.0       28.0
========
             id  homework
10   S201910911     20.39
23   S201910924     10.75
124  S201911315     15.35
========
102.63
5.4.1.2. iloc
  • iloc 是基於行索引和列索引的數字位置來選取資料。這種方法使用索引的數值來選擇資料,從 0 開始計數,適合在你知道具體位置而非標籤時使用。
  • 用法:df.iloc[row_index, column_index]
  • 索引都是基於數字的位置,而不是標籤。
 1: import pandas as pd
 2: 
 3: # 從遠端讀取 CSV 檔案
 4: docURL = 'https://letranger.github.io/PythonCourse/scores.csv'
 5: df = pd.read_csv(docURL)
 6: 
 7: # 使用 iloc 選取前 3 行資料
 8: print(df.iloc[:3])
 9: 
10: # 使用 iloc 選取前 2 行的第 2 和第 3 欄資料
11: print(df.iloc[:2, 1:3])
           id  classparti  typing  homework  midexam  finalexam
0  S201910901         100      72     92.11     48.0       16.0
1  S201910902          96      56     93.42     60.0       40.0
2  S201910903          96      76    102.63     45.0       28.0
   classparti  typing
0         100      72
1          96      56
5.4.1.3. between
  • between 方法可以用來篩選特定區間內的數值資料。例如,如果你需要篩選出某列的值位於某個範圍之間,可以使用 between 方法。
  • 用法:df[’column’].between(left, right, inclusive=True)
  • 這種方法會傳回布林值序列,表示每個值是否位於指定範圍內。
 1: import pandas as pd
 2: 
 3: # 從遠端讀取 CSV 檔案
 4: docURL = 'https://letranger.github.io/PythonCourse/scores.csv'
 5: df = pd.read_csv(docURL)
 6: 
 7: # 使用 between 方法篩選期中考成績在 50 到 60 之間的資料
 8: print(df['midexam'].between(50, 60))
 9: 
10: # 篩選期中考成績在 50 到 55 之間的學生資料
11: midFilter = df['midexam'].between(50, 55)
12: print(df[midFilter])
13: 
0      False
1       True
2      False
3      False
4      False
       ...
207    False
208    False
209    False
210    False
211    False
Name: midexam, Length: 212, dtype: bool
             id  classparti  typing  homework  midexam  finalexam
6    S201910907         101     120     92.11     55.0       20.0
65   S201911029          93      60     82.00     50.0       16.0
72   S201911036          88      80    102.63     53.0       76.0
92   S201911119          82     104     89.47     50.0       20.0
94   S201911121          95     100     88.51     52.0       72.0
109  S201911136          91     100     81.58     51.0        4.0
171  S201911626          98      72     97.37     50.0       75.0

6. 進階分析

6.1. 由其他 column 產生新的 column(重要、實用)

在資料分析過程中,我們經常需要從現有的資料欄位中計算出新的欄位,以便進行進一步的分析。Pandas 提供了靈活且簡便的方法來根據現有欄位生成新的欄位,這可以應用在加總、條件篩選和分組操作上。

6.1.1. 生成新欄位 - 全部指定

我們可以使用運算符來操作 DataFrame 的欄位,並將結果存入新的欄位。這種方式適合應用於所有資料列,並且可以用於進行數值運算。

6.1.1.1. 範例: 生成新欄位 Final(學期總分)
 1: import pandas as pd
 2: 
 3: # 讀取csv
 4: docURL = 'https://letranger.github.io/PythonCourse/scores.csv'
 5: df = pd.read_csv(docURL)
 6: 
 7: # 計算學期總分,並生成新欄位 'Final'
 8: df['Final'] = df.classparti * 0.1 + df.typing * 0.1 + df.homework * 0.2 + df.midexam * 0.3 + df.finalexam * 0.3
 9: 
10: # 查看新增的欄位
11: print(df.head())
           id  classparti  typing  homework  midexam  finalexam   Final
0  S201910901         100      72     92.11     48.0       16.0  54.822
1  S201910902          96      56     93.42     60.0       40.0  63.884
2  S201910903          96      76    102.63     45.0       28.0  59.626
3  S201910904          93      64     86.84     44.0       25.0  53.768
4  S201910905          93      56     42.11      0.0       20.0  29.322

6.1.2. 生成新欄位 - 條件指定

我們還可以根據條件來生成新欄位。使用 loc 方法,可以根據某欄位的值來篩選資料,並指定符合條件的資料對應的欄位值。例如,可以依據成績來指定 PASS 或 FAIL 狀態,或者依據打字速度來分類為 LOW、MID、HIGH。

6.1.2.1. 範例: 依條件新增欄位 PASS 和 TypingSpeed
 1: # 依學期總分新增一個欄位 'PASS'
 2: df.loc[df.Final < 60, 'PASS'] = False
 3: df.loc[df.Final >= 60, 'PASS'] = True
 4: 
 5: # 依據打字速度新增一個分類欄位 'TypingSpeed'
 6: df.loc[df.typing < 30, 'TypingSpeed'] = 'LOW'
 7: df.loc[df.typing.between(30, 60), 'TypingSpeed'] = 'MID'
 8: df.loc[df.typing > 60, 'TypingSpeed'] = 'HIGH'
 9: 
10: # 查看結果
11: print(df.head(3))
           id  classparti  typing  homework  midexam  finalexam   Final   PASS TypingSpeed
0  S201910901         100      72     92.11     48.0       16.0  54.822  False        HIGH
1  S201910902          96      56     93.42     60.0       40.0  63.884   True         MID
2  S201910903          96      76    102.63     45.0       28.0  59.626  False        HIGH

6.2. 交叉分析:分組與資料轉置

6.2.1. 範例:依打字速度分組與資料統計

 1: # 依據打字速度分組,計算每組的學期總分平均值
 2: print('---依打字速度分組---')
 3: print(df.groupby('TypingSpeed')['Final'].mean())
 4: 
 5: # 依據 PASS 分組,計算打字成績和作業成績的平均值
 6: print(df.groupby('PASS')[['typing', 'homework']].mean())
 7: 
 8: # 將結果轉置,查看不同分組下的平均打字成績和作業成績
 9: print('---置換row/column(轉90度)---')
10: print(df.groupby('PASS')[['typing', 'homework']].mean().T)
---依打字速度分組---
TypingSpeed
HIGH    69.977451
LOW     68.517333
MID     64.086303
Name: Final, dtype: float64
          typing   homework
PASS
False  77.567568  76.409054
True   84.525547  96.350730
---置換row/column(轉90度)---
PASS          False      True
typing    77.567568  84.525547
homework  76.409054  96.350730

6.3. 資料檔下載: scores.csv

7. 資料視覺化

7.1. Bar chart

 1: # 載入函式庫
 2: import pandas as pd
 3: import matplotlib.pyplot as plt
 4: 
 5: # 讀取csv
 6: docURL = 'https://letranger.github.io/PythonCourse/scores.csv'
 7: df = pd.read_csv(docURL)
 8: 
 9: # 計算總分'
10: df['Final'] = df.classparti*.1 + df.typing*.1 + df.homework*.2 + df.midexam*.3 + df.finalexam*.3
11: 
12: # create new column according to typing speed
13: df.loc[df.typing < 30, 'TypingSpeed' ] = 'Level-1'
14: df.loc[df.typing.between(30, 60), 'TypingSpeed' ] = 'Level-2'
15: df.loc[df.typing > 60, 'TypingSpeed' ] = 'Level-3'
16: 
17: x = df.groupby('TypingSpeed')[['homework','classparti']].mean()
18: print(x)
19: # 關於圖表的屬性設定方式
20: fig = df.groupby('TypingSpeed')[['homework','classparti']].mean().plot(kind='bar', title="XXX", rot=0, legend=True)
21: fig.set_xlabel("Typing Speed")
22: fig.set_ylabel("score")
23: #savefig = fig.get_figure() # 如果不存圖檔就不用設定這行
24: # 關於圖表的屬性設定方式
25: fig1 = df.groupby('TypingSpeed')[['homework','classparti']].mean().T.plot(kind='bar', title="XXX", rot=0, legend=True)
26: fig1.set_xlabel("Subject")
27: fig1.set_ylabel("score")
28: #savefig1 = fig1.get_figure()# 如果不存圖檔就不用設定這行
29: 
30: # 如果不存圖檔就不用執行以下程式
31: savefig.savefig('images/pandasPlot1.png', bbox_inches='tight')
32: savefig1.savefig('images/pandasPlot10.png', bbox_inches='tight')
              homework  classparti
TypingSpeed
Level-1      96.053333   87.666667
Level-2      85.273939   88.696970
Level-3      90.053920   93.159091

pandasPlot1.png

Figure 2: Pandas plot bar chart

pandasPlot10.png

Figure 3: Pandas plot bar chart

7.2. Regression line chart

 1: # 載入函式庫
 2: import pandas as pd
 3: import seaborn as sns
 4: 
 5: # 讀取csv
 6: docURL = 'https://letranger.github.io/PythonCourse/scores.csv'
 7: df = pd.read_csv(docURL)
 8: 
 9: sns.regplot(x="midexam", y='finalexam', data=df);
10: 
11: #fig = sns.regplot(x="midexam", y='finalexam', data=df);
12: #savefig = fig.get_figure()
13: #savefig.savefig('images/PandasPlot4.png')
14: 

PandasPlot4.png

Figure 4: Pandas plot scatter chart

7.3. Pie chart

7.3.1. DEMO

 1: # 載入函式庫
 2: import pandas as pd
 3: 
 4: # 讀取csv
 5: docURL = 'https://letranger.github.io/PythonCourse/scores.csv'
 6: df = pd.read_csv(docURL)
 7: 
 8: # 計算總分'
 9: df['Final'] = df.classparti*.1 + df.typing*.1 + df.homework*.2 + df.midexam*.3 + df.finalexam*.3
10: 
11: # create new column according to typing speed
12: df.loc[df.typing < 60, 'TypingSpeed' ] = 'Level-1'
13: df.loc[df.typing.between(60, 80), 'TypingSpeed' ] = 'Level-2'
14: df.loc[df.typing > 80, 'TypingSpeed' ] = 'Level-3'
15: print(df.groupby('TypingSpeed').count())
16: df.groupby('TypingSpeed')['TypingSpeed'].count().plot(kind='pie', title="XXX", rot=0, legend=True)
17: # 如果不存圖檔就不用執行以下程式
18: #fig = df.groupby('TypingSpeed')['TypingSpeed'].count().plot(kind='pie', title="XXX", rot=0, legend=True)
19: #savefig = fig.get_figure()
20: #savefig.savefig('images/pandasPlot2.png', bbox_inches='tight')

id classparti typing homework midexam finalexam Final
TypingSpeed
Level-1 25 25 25 25 25 25 25
Level-2 86 86 86 86 86 86 86
Level-3 101 101 101 101 100 101 100

pandasPlot2.png

Figure 5: Pandas plot pie chart

7.3.2. 如何避免圖例擋住圖表

7.4. Scatter chart

 1: # 載入函式庫
 2: import pandas as pd
 3: 
 4: # 讀取csv
 5: docURL = 'https://letranger.github.io/PythonCourse/scores.csv'
 6: df = pd.read_csv(docURL)
 7: 
 8: df[['midexam','finalexam']].plot(kind='scatter', x=1, y=0)
 9: fig = df[['midexam','finalexam']].plot(kind='scatter', x=1, y=0)
10: 
11: # 如果不存圖檔就不用執行以下程式
12: #savefig = fig.get_figure()
13: #savefig.savefig('images/PandasPlot3.png')

PandasPlot3.png

Figure 6: Pandas plot scatter chart

7.5. Haxbin chart

 1: # 載入函式庫
 2: import pandas as pd
 3: 
 4: # 讀取csv
 5: docURL = 'https://letranger.github.io/PythonCourse/scores.csv'
 6: df = pd.read_csv(docURL)
 7: 
 8: df[['midexam','finalexam']].plot(kind='hexbin', x=1, y=0, gridsize=25)
 9: 
10: fig = df[['midexam','finalexam']].plot(kind='hexbin', x=1, y=0, gridsize=25)
11: #savefig = fig.get_figure()
12: #savefig.savefig('images/PandasPlot6.png')

PandasPlot6.png

Figure 7: Pandas plot hexbin chart

8. [作業]   TNFSH

8.1. 403期中考得分統計

  • 原始數據

csv.jpg

Figure 8: CSV 內容

  • cs109score.csv為 T 市某校的資訊科線上期中考系統所匯出的成績檔,該次考試共計 10 題,其中
    • 前 5 題(A,B,C,D,E)為基本題,每題 100 分,
    • 後 4 題為加分題(Bonus1~Bonus4),每題 25 分
    • 本份考卷總分:600;
    • 總得分除以 5 即為期中考得分
    • 此次期中考總分 120分。

8.1.1. 任務 1 (10%):

  • 將有缺失值的部份以 0 分取代。
  • 直接輸出前10筆資料

8.1.2. 任務 2 (20%):

  • 求出每個人的原始總分(即所有分數),新增的欄位名稱為TOTAL
  • 新增欄位SCORE, 其值為每個人的實際得分(原始總分TOTAL除以 5)
  • 直接輸出前10筆資料

8.1.3. 任務 3 (20%)

  • 新增班級欄位(已知學號的前四碼為入學年份、接下來的三碼為班級、末兩碼為座號)
  • 輸出前10筆資料(依SCORE由高到低排序)

8.1.4. 任務 4 (10%):

求所有受試者第 B 及 B1 兩題的 scatter plot 以及 regression line。如下圖:

task8.png

Figure 9: 任務3

8.1.5. 任務 5 (20%):

  • 新增ABILITY欄位,依以下條件填入類別
    • SCORE <= 50, ABILITY: ’LEVEL-1’
    • 50 < SCORE < 80, ABILITY: ’LEVEL-2’
    • SCORE >= 80, ABILITY: ’LEVEL-3’

8.1.6. 任務 6 (20%):

交叉分析,依ABILITY分組,查看此三組學生的前三題(A, B, C)得分情況,並繪製圖表

pandastask5.png

Figure 10: 任務5

8.1.7. Solution

8.1.7.1. 任務1
 1: import numpy as np
 2: import pandas as pd
 3: import seaborn as sns
 4: import matplotlib.pyplot as plt
 5: 
 6: origdf = pd.read_csv("cs109score.csv")
 7: 
 8: plt.rcParams['font.sans-serif'] = ['SimHei'] # 步驟一(替換sans-serif字型)
 9: plt.rcParams['axes.unicode_minus'] = False  # 步驟二(解決座標軸負數的負號顯示問題)
10: ##1
11: #origdf.fillna(0, inplace=True)
12: origdf = origdf.fillna(0)
13: print(origdf.head(10))
          學號      A      B      C      D      E    B1     B2     B3   B4
0  201910401  100.0   66.0   75.0    0.0  100.0   0.0    0.0    0.0  0.0
1  201910402  100.0  100.0  100.0  100.0  100.0   0.0    0.0  100.0  0.0
2  201910403  100.0  100.0   80.0  100.0  100.0   0.0   75.0    0.0  0.0
3  201910404  100.0  100.0  100.0   75.0  100.0   0.0    0.0    0.0  0.0
4  201910405  100.0  100.0  100.0    0.0   50.0   0.0    0.0    0.0  0.0
5  201910406  100.0   20.0   25.0    0.0  100.0   0.0    0.0    0.0  0.0
6  201910407  100.0  100.0  100.0    0.0   50.0   0.0    0.0    0.0  0.0
7  201910408    0.0    0.0    0.0    0.0    0.0   0.0    0.0    0.0  0.0
8  201910409  100.0  100.0   75.0  100.0   25.0  25.0  100.0    0.0  0.0
9  201910410  100.0   60.0  100.0  100.0  100.0   0.0    0.0    0.0  0.0
8.1.7.2. 任務2
 1: import numpy as np
 2: import pandas as pd
 3: import seaborn as sns
 4: import matplotlib.pyplot as plt
 5: 
 6: origdf = pd.read_csv("cs109score.csv")
 7: 
 8: plt.rcParams['font.sans-serif'] = ['SimHei'] # 步驟一(替換sans-serif字型)
 9: plt.rcParams['axes.unicode_minus'] = False  # 步驟二(解決座標軸負數的負號顯示問題)
10: ##1
11: #origdf.fillna(0, inplace=True)
12: origdf = origdf.fillna(0)
13: ##2
14: items = ['A', 'B', 'C', 'D', 'E', 'B1', 'B2' ,'B3', 'B4']
15: origdf['TOTAL'] = origdf['A']+origdf['B']+origdf['C']+origdf['D']+origdf['E']+origdf['B1']+origdf['B2']+origdf['B3']+origdf['B4']
16: 
17: 
18: origdf['SCORE'] = origdf['TOTAL']/5
19: print('=========2============')
20: print(origdf.head(10))
21: ##4
22: origdf['班級'] = origdf['學號'].astype(str).str[4:7]
23: 
24: print(origdf.sort_values(by='SCORE', ascending=False).head(10))
25: 
26: origdf.loc[origdf.SCORE < 60, 'ABILITY' ] = 'LEVEL-1'
27: origdf.loc[origdf.SCORE.between(60, 80), 'ABILITY' ] = 'LEVEL-2'
28: origdf.loc[origdf.SCORE > 80, 'ABILITY' ] = 'LEVEL-3'
29: print('=========4============')
30: print(origdf.head(10))
31: 
32: fig = origdf.groupby('ABILITY')[['A','B','C']].mean().plot(kind='bar', title="Cross Analysis", rot=0, legend=True)
33: fig.set_xlabel("Level")
34: fig.set_ylabel("Score")
35: fig.legend(loc="center right")
36: savefig = fig.get_figure()# 如果不存圖檔就不用設定這行
37: savefig.savefig('images/pandastask5.png', bbox_inches='tight')
38: ##5
39: #y_pos = np.arange(len(items))
40: #plt.bar(y_pos, origdf[items].mean(), color = ['b','g','r','c','m','y'], alpha=0.5)
41: #plt.xticks(y_pos, items)
42: #plt.xlabel('試題')
43: #plt.savefig('images/task5.png')
44: #plt.clf()
45: ###6
46: #fig = origdf.groupby('班級')['分數'].mean().plot(kind='barh', color = ['b','g','r','c','m','y'], alpha=0.5)
47: #fig.set_xlabel('score')
48: #fig.set_ylabel('班級', rotation=0)
49: #resfig = fig.get_figure()
50: #resfig.savefig('images/task6.png', bbox_inches='tight')
51: ###7
52: #df119 = origdf[(origdf.班級 == '119')]
53: #plt.clf()
54: ##print(df119[items].mean())
55: #plt.pie(df119[items].mean(), labels = items)
56: #plt.savefig('images/task7.png', dpi=300)
57: ###8
58: #import seaborn as sns
59: #plt.clf()
60: #fig = sns.regplot(x="A",  y="B", data=origdf)
61: #                       resfig = fig.get_figure()
62: #resfig.savefig("images/task8.png")
=========2============
          學號      A      B      C      D  ...     B2     B3   B4  TOTAL  SCORE
0  201910401  100.0   66.0   75.0    0.0  ...    0.0    0.0  0.0  341.0   68.2
1  201910402  100.0  100.0  100.0  100.0  ...    0.0  100.0  0.0  600.0  120.0
2  201910403  100.0  100.0   80.0  100.0  ...   75.0    0.0  0.0  555.0  111.0
3  201910404  100.0  100.0  100.0   75.0  ...    0.0    0.0  0.0  475.0   95.0
4  201910405  100.0  100.0  100.0    0.0  ...    0.0    0.0  0.0  350.0   70.0
5  201910406  100.0   20.0   25.0    0.0  ...    0.0    0.0  0.0  245.0   49.0
6  201910407  100.0  100.0  100.0    0.0  ...    0.0    0.0  0.0  350.0   70.0
7  201910408    0.0    0.0    0.0    0.0  ...    0.0    0.0  0.0    0.0    0.0
8  201910409  100.0  100.0   75.0  100.0  ...  100.0    0.0  0.0  525.0  105.0
9  201910410  100.0   60.0  100.0  100.0  ...    0.0    0.0  0.0  460.0   92.0

[10 rows x 12 columns]
            學號      A      B      C      D  ...     B3     B4  TOTAL  SCORE   班級
52   201910517  100.0  100.0  100.0  100.0  ...  100.0  100.0  800.0  160.0  105
99   201910627  100.0  100.0  100.0  100.0  ...  100.0  100.0  760.0  152.0  106
184  201911905  100.0  100.0  100.0  100.0  ...   50.0  100.0  750.0  150.0  119
56   201910521  100.0  100.0  100.0  100.0  ...  100.0   80.0  740.0  148.0  105
189  201911910  100.0  100.0  100.0  100.0  ...    0.0  100.0  725.0  145.0  119
116  201910707  100.0  100.0  100.0  100.0  ...   20.0  100.0  720.0  144.0  107
42   201910507  100.0  100.0  100.0  100.0  ...  100.0  100.0  700.0  140.0  105
136  201910727  100.0  100.0  100.0  100.0  ...   20.0   20.0  690.0  138.0  107
188  201911909  100.0  100.0  100.0  100.0  ...   25.0   50.0  675.0  135.0  119
181  201910836  100.0  100.0  100.0  100.0  ...   20.0   20.0  640.0  128.0  108

[10 rows x 13 columns]
=========4============
          學號      A      B      C      D  ...   B4  TOTAL  SCORE   班級  ABILITY
0  201910401  100.0   66.0   75.0    0.0  ...  0.0  341.0   68.2  104  LEVEL-2
1  201910402  100.0  100.0  100.0  100.0  ...  0.0  600.0  120.0  104  LEVEL-3
2  201910403  100.0  100.0   80.0  100.0  ...  0.0  555.0  111.0  104  LEVEL-3
3  201910404  100.0  100.0  100.0   75.0  ...  0.0  475.0   95.0  104  LEVEL-3
4  201910405  100.0  100.0  100.0    0.0  ...  0.0  350.0   70.0  104  LEVEL-2
5  201910406  100.0   20.0   25.0    0.0  ...  0.0  245.0   49.0  104  LEVEL-1
6  201910407  100.0  100.0  100.0    0.0  ...  0.0  350.0   70.0  104  LEVEL-2
7  201910408    0.0    0.0    0.0    0.0  ...  0.0    0.0    0.0  104  LEVEL-1
8  201910409  100.0  100.0   75.0  100.0  ...  0.0  525.0  105.0  104  LEVEL-3
9  201910410  100.0   60.0  100.0  100.0  ...  0.0  460.0   92.0  104  LEVEL-3

[10 rows x 14 columns]

task5.png

Figure 11: task5

task6.png

Figure 12: task6

task7.png

Figure 13: task7

task8.png

Figure 14: task8

8.2. 進階練習

一dataframe如下

import numpy as np
import pandas as pd
scores = {'Math': [900, 50, 70, 80],
          'English': [60, 30, 90, 50],
          'History': [33, 75, np.NaN, np.NaN]}
df = pd.DataFrame(scores, index=['Simon', 'Allen', 'Jimmy', 'Vanessa'])

試解決以下問題:

  1. 列出Math分數>100資料
  2. 將Siman之Math改為90分
  3. 計算History遺漏值筆數
  4. 以History平均值取代History中遺漏值
  5. 新增“平均”欄位,計算四人各科平均
  6. 新增“名次”欄位,以四人平均分數為排序依據
  7. 列出平均不及格者
  8. 列出數學最高分者姓名

9. 教學影片

Footnotes:

Author: Yung-Chin Yen

Created: 2024-11-28 Thu 21:37