# Pandas ###### tags: `python` `pandas` ## 介i紹 Pandas模組是Python語言一個高效能、簡易使用的資料操作和分析工具,可以將它看作是微軟Excel或是MacOS Numbers試算表軟體的程式版本,就像是透過Python來操作像試算表內的資料。 主要特色如下: 1. 方便簡單的異質數據讀取、轉換和處理。 2. 提供兩種主要的資料結構:Series用來處理時間序列相關的資料,是個擁有標籤的一維陣列;DataFrame則是用來處理像表格一樣的二維的資料,並且可以隨意更改結構和任意欄位的資料型態。 3. 資料載入Pandas的資料結構物件後,可以提供的方法,統一進行資料處理,如合併、補值,過濾或取代等等。 4. 多輸入來源及多輸出整合,例如:可以從資料庫讀取資料進行處理後,可以輸出到資料庫或檔案等等。 ## 安裝 安裝語法如下: ``` $ pip3 install pandas ``` > 官方網站:https://pandas.pydata.org/ ## Series #### 建立Series物件 ```python import pandas as pd s = pd.Series([13, 30, 77, 6, 111, 10]) print(s) ``` 執行結果: ``` 0 13 1 30 2 77 3 6 4 111 5 10 dtype: int64 ``` 說明: 1. Series就像一維陣列一樣,第一行從0~5為後面資料的索引值,和Python內建的陣列(list)一樣,預設索引值從0開始。 2. dtype表示Series內資料型態為int64。 #### 建立自訂索引值的Series物件 ``` import pandas as pd names = ['Aaron', 'Amber', 'Andy', 'Apple', 'Astrid'] no = [32, 12, 42, 2, '102'] s = pd.Series(names, index=no) print(s) print(s.index) print(s.values) ``` 執行結果: ``` 32 Aaron 12 Amber 42 Andy 2 Apple 102 Astrid dtype: object Int64Index([32, 12, 42, 2, 102], dtype='int64') ['Aaron' 'Amber' 'Andy' 'Apple' 'Astrid'] ``` 說明: 透過傳入name這個list來建立Series物件,並指定index參數為no這個list作為索引值。 > 補充: > > 1. 兩個list的長度必須一樣,否則會有「ValueError: Length of passed values is 5, index implies 4.」錯誤。 > 2. 索引可以是整數也可以是字串。 #### 取出Series物件資料 ##### 取出一筆資料 ``` import pandas as pd s = pd.Series([13, 30, 77, 6, 111, 10]) # 使用索引來取出資料 print(s[0]) ``` 執行結果: ``` 13 ``` ##### 取出多筆資料 ``` import pandas as pd s = pd.Series([13, 30, 77, 6, 111, 10]) # 使用索引list來一次取出多筆資料 print(s[[0, 2, 4]]) ``` 執行結果: ``` 0 13 2 77 4 111 dtype: int64 ``` > 注意: > > 1. 索引清單為一個list。 > 2. 取出的值為一個新的Series物件。 #### 進行運算 直接對Series物件做四則運算。 ``` import pandas as pd s = pd.Series([13, 30, 77, 6, 111, 10]) print((s + 1) * 2) ``` 執行結果: ``` 0 28 1 62 2 156 3 14 4 224 5 22 dtype: int64 ``` ## DataFrame DataFrame結構為一個表格,類似微軟Excel或蘋果Numbers試算表: 1. 有一個排序的欄位集合。 2. 每個欄位內的資料型態是固定的。 3. 不同欄位資料型態可以不同。 > **補充:** > > 在Excel內,橫的為row,稱為列,而直的為column,稱為欄或行,但須注意,中國大陸對行與列的稱呼和台灣剛好相反:橫的為行,直的為列。 #### 建立DataFrame ``` import pandas as pd data = { '學號': [1, 2, 3, 4, 5], '姓名': ['Aaron', 'Amber', 'Apple', 'Andy', 'Astrid'], '國文': [100, 90, 80, 70, 60], '英文': [90, 80, 70, 60, 50], '數學': [100, 95, 85, 75, 65] } df = pd.DataFrame(data) print(df) ``` 執行結果: ``` 學號 姓名 國文 英文 數學 0 1 Aaron 100 90 100 1 2 Amber 90 80 95 2 3 Apple 80 70 85 3 4 Andy 70 60 75 4 5 Astrid 60 50 65 ``` 說明: 透過使用Python字典(dict)來建立DataFrame;左邊第一行為自動產生的預設索引。 #### 建立自訂索引的DataFrame 如果建立時沒有指定索引,預設會是從0開始,和Series一樣,我們也可以提供一個清單(list) 來自訂索引。 ``` import pandas as pd data = { '手機': ['Samsung Flip', 'Apple iPhone 12', 'Sony Z1'], '價格': [50000, 40000, 30000], '折扣': [0.8, 0.95, 0.75] } index = ['0101', '0102', '0103'] df = pd.DataFrame(data, index=index) print(df) ``` 執行結果: ``` 手機 價格 折扣 0101 Samsung Flip 50000 0.80 0102 Apple iPhone 12 40000 0.95 0103 Sony Z1 30000 0.75 ``` 說明: 三個索引分別對應三筆資料,索引和資料筆數必須對應,否則會出現錯誤。 ##### 另一種建立自訂索引的方式 ``` df = pd.DataFrame(data) df.index = index ``` #### 改變DataFrame欄位順序 建立DataFrame時可以同時指定一個清單(list)給`columns`參數,就會改變原本字典(dict)裡的欄位順序。 ``` import pandas as pd data = { '手機': ['Samsung Flip', 'Apple iPhone 12', 'Sony Z1'], '價格': [50000, 40000, 30000], '折扣': [0.8, 0.95, 0.75] } index = ['0101', '0102', '0103'] df = pd.DataFrame(data, columns=['折扣', '手機', '價格'], index=index) print(df) ``` 執行結果: ``` 折扣 手機 價格 0101 0.80 Samsung Flip 50000 0102 0.95 Apple iPhone 12 40000 0103 0.75 Sony Z1 30000 ``` #### 轉換欄與列 ``` print(df.T) ``` 使用`T`屬性,可以改變結構,讓欄變成列,列變成欄。 #### 匯入 | 方法 | 說明 | | --------------------- | ------------------------------------------------------ | | read_csv(filename) | 匯入CSV格式檔案。 | | read_json(filename) | 匯入JSON格式檔案。 | | read_html(filename) | 匯入HTML格式檔案,Pandas僅會抽出\<table\>標籤內資料。 | | read_excel(filename) | 匯入Excel檔案。 | | read_sql(query, conn) | 匯入資料庫資料,query為SQL查詢語法,conn為資料庫連線。 | > 補充: > > `read_excel()`方法需要安裝`openpyxl`模組。 ##### 範例: ``` import pandas as pd from sqlalchemy import create_engine df1 = pd.read_csv('test.csv', encoding='utf-8') print('df1\n-----\n', df1) df2 = pd.read_json('test.json') print('df2\n-----\n', df2) df3 = pd.read_html('test.html') print('df3\n-----\n', df3) df4 = pd.read_excel('test.xls', index_col=0) print('df4\n-----\n', df4) engine = create_engine('postgres://{username}:{password}@{host}:5432/{database}') df5 = pd.read_sql('SELECT * FROM test', engine) print('df5\n-----\n', df5) ``` > 補充: > > 指定index_col=0,就不會出現unnamed欄位(其實就是原本的索引值欄位)。 #### 匯出 | 方法 | 說明 | | ------------------------ | -------------------------------------------------------- | | to_csv(filename) | 匯出成CSV格式檔案。 | | to_json(filename) | 匯出成JSON格式檔案。 | | to_html(filename) | 匯出成HTML格式檔案。 | | to_excel(filename) | 匯出成Excel格式檔案。 | | to_sql(table_name, conn) | 匯出到資料庫,table_name為資料表名稱,conn為資料庫連線。 | > 補充: > > 1. to_excel()方法需要安裝openpyxl模組。 ##### 範例 ``` import pandas as pd from sqlalchemy import create_engine data = { '手機': ['Samsung Flip', 'Apple iPhone 12', 'Sony Z1'], '價格': [50000, 40000, 30000], '折扣': [0.8, 0.95, 0.75] } index = ['0101', '0102', '0103'] df = pd.DataFrame(data, columns=['折扣', '手機', '價格'], index=index) df.to_csv('test.csv', index=False, encoding='utf-8') df.to_json('test.json') df.to_html('test.html', encoding='utf-8') df.to_excel('test.xls') engine = create_engine('postgres://{username}:{password}@{host}:5432/{database}') df.to_sql('test', engine, if_exists='replace') ``` > 補充: > > sqlalchemy模組安裝:`pip3 installsqlalchemy` #### 走訪每一筆紀錄 #### `iterrows()` ##### 範例 ``` ... 以上省略 ... for index, row in df.iterrows(): print(index, row) ``` > 補充: > > `row`為一個Series物件。 ## 顯示基本資訊 #### `head()`方法 ``` df.head() # 顯示前五筆資料(預設) df.head(3) # 顯示前三筆資料 ``` > 補充: > > DataFrame和Series皆提供此方法。 #### `tail()`方法 ``` df.tail() # 顯示最後五筆資料(預設) df.tail(3) # 顯示最後三筆資料 ``` > 補充: > DataFrame和Series皆提供此方法。 #### `info()`方法 取得DataFrame的摘要資訊。 ###### 輸出範例: ``` <class 'pandas.core.frame.DataFrame'> Index: 3 entries, 0101 to 0103 Data columns (total 3 columns): # Column Non-Null Count Dtype --- ------ -------------- ----- 0 折扣 3 non-null float64 1 手機 3 non-null object 2 價格 3 non-null int64 dtypes: float64(1), int64(1), object(1) memory usage: 204.0+ bytes ``` #### `len()`方法 取得Series或DataFrame的資料筆數。 #### `shape`屬性 取得Series或DataFrame的輪廓。 ###### Series的shape輸出範例: ``` (5,) ``` ##### DataFrame的shape輸出範例: ``` (3, 3) ``` #### `reset_index()` 重新設定index ```python= df.reset_index(inplace=True, drop=True) ``` - inplace: 直接修改原本的DataFrame - drop: 拋棄原本的index,如果設為False,則會保留舊的index為一個新的欄位 #### `to_numeric()` 轉換Series的欄位資料 ``` pd.to_numeric(series, downcast='integer') ``` #### `astype()` 將Series或DataFrame內的欄位資料做轉型 ``` # 將DataFrame全部欄位的資料型態轉為int df = df.astype(int) # 將欄位a轉型成int64 dtype而且欄位b轉型成complex型態 df = df.astype({"a": int, "b": complex}) # 將Series資料型態轉為float16 s = s.astype(np.float16) # 將Series型態轉為Python strings s = s.astype(str) ``` ## 操作資料 #### 選取(select) - `df[欄名]` - `df[列名開始:列名結束]` - `df[列名, 欄名]` ##### 建立資料DataFrame: ``` import pandas as pd data = { '學號': [1, 2, 3, 4, 5], '姓名': ['Aaron', 'Amber', 'Apple', 'Andy', 'Astrid'], '國文': [100, 90, 80, 70, 60], '英文': [90, 80, 70, 60, 50], '數學': [100, 95, 85, 75, 65] } index = ['A', 'B', 'C', 'D', 'E'] df = pd.DataFrame(data, index=index) ``` ##### 取得「姓名」欄位前兩筆資料 ``` print(df['姓名'].head(2)) ``` 執行結果: ``` A Aaron B Amber Name: 姓名, dtype: object ``` > 其結果為一個Series 也可這樣寫: ``` print(df.姓名.head(2)) ``` ##### 取得「學號」和「姓名」的前兩筆資料 ``` print(df[['學號', '姓名']].head(2)) ``` 執行結果: ``` 學號 姓名 A 1 Aaron B 2 Amber ``` > 其結果為一個DataFrame #### 選取特定範圍的資料 可以使用像Python清單(list)的索引切片運算子來選擇一個範圍的資料: ``` print(df[0:3]) ``` 執行結果: ``` 學號 姓名 國文 英文 數學 A 1 Aaron 100 90 100 B 2 Amber 90 80 95 C 3 Apple 80 70 85 ``` > 不包含索引3的資料 也可以使用自訂索引的名稱來選擇資料: ``` print(df['B':'D']) ``` 執行結果: ``` 學號 姓名 國文 英文 數學 B 2 Amber 90 80 95 C 3 Apple 80 70 85 D 4 Andy 70 60 75 ``` > 注意: > > 與Python清單索引切片不同,這裡會包含最後一筆D欄位的資料。 #### 使用loc索引器來選取資料 - `df.loc[列名]` :取得特定的列的資料 - `df.loc[:, 行名]` : 取得特定的行的資料 - `df.loc[列名, 行名]` :取得特定行列的資料 ##### 取得「A」索引資料: ``` print(df.loc['A']) ``` > 回傳值為一個Series物件。 ##### 取得「學號」和「姓名」欄位的全部資料: ``` print(df.loc[:, ['學號', '姓名']]) ``` 執行結果: ``` 學號 姓名 A 1 Aaron B 2 Amber C 3 Apple D 4 Andy E 5 Astrid ``` > 回傳值為一個DataFrame物件。 ##### 取得B、C、D索引這三列的「學號」跟「姓名」兩個欄位資料。 ``` print(df.loc['B':'D', ['學號', '姓名']]) ``` 執行結果: ``` 學號 姓名 B 2 Amber C 3 Apple D 4 Andy ``` > 回傳值回一個DataFrame物件。 ##### 取得指定的欄位資料 ``` print(df.loc['B', '學號']) ``` 執行結果: ``` 2 ``` 也可以這樣寫: ``` print(df.loc['B']['學號']) ``` #### 使用iloc位置索引器選擇資料 #### 與`loc`的差別為: 1. `loc`是以名稱來定位資料,而`iloc`是以位置來定位資料。 2. `loc`的切片會包含結束位置的資料,而`iloc`的切片不會包含結束位置的資料。 ``` print(df.iloc[2]) # 第3筆 print('-----') print(df.iloc[3:5, 1:3]) # 第4、5列的2、3欄位資料 ``` 執行結果: ``` 學號 3 姓名 Apple 國文 80 英文 70 數學 85 Name: C, dtype: object ----- 姓名 國文 D Andy 70 E Astrid 60 ``` ##### 使用切割列跟欄的方式: ``` print(df.iloc[1:3, :]) # 選取第2、3列資料 print('-----') print(df.iloc[:, 1:3]) # 選取第2、3欄資料 ``` 執行結果: ``` 學號 姓名 國文 英文 數學 B 2 Amber 90 80 95 C 3 Apple 80 70 85 ----- 姓名 國文 A Aaron 100 B Amber 90 C Apple 80 D Andy 70 E Astrid 60 ``` ##### 挑選不連續資料 ``` print(df.iloc[[1, 4], [0, 3]]) # 選取第2、5列的第1、4欄位資料 ``` 執行結果: ``` 學號 英文 B 2 80 E 5 50 ``` ##### 選取的特定一個欄位值 ``` print(df.iloc[1, 1]) # 選取第2列的第2個欄位資料 ``` 執行結果: ``` Amber ``` #### 過濾(filter) ##### 選取國文分數超過80分的資料 ``` print(df[df.國文 > 80]) ``` ##### 選取國文分數為100跟90分的資料 ``` print(df[df['國文'].isin([100, 90])]) ``` ##### 選取國文跟數學都是100的資料 ``` print(df[(df.國文 == 100) & (df.數學 == 100)]) ``` ##### 選取姓名開頭為「Aa」的資料 ``` print(df[df['姓名'].str.startswith('Aa')]) ``` #### 排序(sort) ##### 依照國文分數來排序資料 ``` df2 = df.set_index('國文', inplace=True) df2.sort_index(ascending=True, inplace=True) print(df2) ``` 說明: 1. 先將「國文」欄位指定為索引。 2. 呼叫`set_index()`方法來的對索引做排序。 3. `ascending=True`表示由小到的大排序。 4. `inplace=True`表示取代原本的`df2`資料,如果為`False`,該方法會回傳一個新的DataFrame。 ##### 直接指定「數學」欄位做排序,由低到高 ``` df2 = df.sort_values('數學', ascending=True) print(df2) ``` ##### 指定用「國文」、「英文」和「數學」三個欄位做排序,由低到高: ``` df2 = df.sort_values(['國文', '英文', '數學'], ascending=True) print(df2) ``` #### 新增(insert) ##### 指定不存在的標籤來新增資料 ``` df.loc['F'] = [6, 'Abner', 77, 66, 88] print(df) ``` ##### ~~建立Series物件後透過`append()`方法來新增~~ ``` s = pd.Series({'學號':6, '姓名': 'Abner', '國文':77, '英文':66, '數學':88}) df2 = df.append(s, ignore_index=True) print(df2) ``` > 補充: > > ~~透過`append()`新增後會產生一個新的DataFrame物件,原來的DataFrame物件不會有變化。~~ > > Pandas 2.0移除`append()`方法,可以使用`concat()`方法來替代 ##### 使用`concat()`方法來新增資料 ``` df_result = pd.Dataframe(...) new_df = pd.Dataframe(...) df_result = pd.concat([df_result, new_df]) ``` ##### 指定不存在的欄位來新增欄位資料 ``` df.loc[:, '程式設計'] = [100, 80, 75, 95, 80, 66] ``` 或 ``` df['程式設計'] = [100, 80, 75, 95, 80, 66] ``` #### 更新(update) ##### 更新單一個欄位值 ``` df.loc['B', '英文'] = 100 # 將索引B的英文成績改為100 df.iloc[0, 1] = 'Aaron Ho' # 將第1列的第二欄位改成'Aaron Ho' print(df) ``` 執行結果: ``` 學號 姓名 國文 英文 數學 A 1 Aaron Ho 100 90 100 B 2 Amber 90 100 95 C 3 Apple 80 70 85 D 4 Andy 70 60 75 E 5 Astrid 60 50 65 ``` ##### 更新整筆紀錄 ``` s = [1, 'Aaron', 99, 99, 99] df.loc['A'] = s print(df) ``` 執行結果: ``` 學號 姓名 國文 英文 數學 A 1 Aaron 99 99 99 B 2 Amber 90 100 95 C 3 Apple 80 70 85 D 4 Andy 70 60 75 E 5 Astrid 60 50 65 ``` ##### 更新某個欄位的全部資料 ``` df.loc[:, '學號'] = [11, 12, 13, 14, 15] ``` 執行結果: ``` 學號 姓名 國文 英文 數學 A 11 Aaron 99 99 99 B 12 Amber 90 100 95 C 13 Apple 80 70 85 D 14 Andy 70 60 75 E 15 Astrid 60 50 65 ``` #### 刪除(delete) ##### 刪除索引為「B」、「C」的兩列資料 ``` df2 = df.drop(['B', 'C']) print(df2) ``` ##### 刪除「學號」欄位: ``` df2 = df.drop(['學號'], axis=1) print(df2) ``` > 補充: > > 1. 加上`axis=1`參數代表要刪除的是欄位。 > > 2. 如果只是要刪除一個欄位,也可以寫成`df2 = df.drop('學號', axis=1)` #### 建立空的DataFrame物件 ``` columns = ['學號', '姓名', '國文', '英文', '數學'] index = [1, 2, 3, 4, 5] df_empty = pd.DataFrame(None, index=index, columns=columns) print(df_empty) ``` 執行結果: ``` 學號 姓名 國文 英文 數學 1 NaN NaN NaN NaN NaN 2 NaN NaN NaN NaN NaN 3 NaN NaN NaN NaN NaN 4 NaN NaN NaN NaN NaN 5 NaN NaN NaN NaN NaN ``` > 會建立一個所有欄位值都是None DataFrame物件。 #### 複製DataFrame 建立一個完全一樣的DataFrame物件。 ``` df_copy = df.copy() ``` #### 連接(concat) ``` import pandas as pd data1 = { '商品': ['計算機', '剪刀', '鉛筆'], '售價': [200, 100, 20], '折扣': [0.9, 0.8, 0.7] } df1 = pd.DataFrame(data1) data2 = { '商品': ['膠帶', '修正液'], '售價': [40, 110], '折扣': [0.9, 0.8] } df2 = pd.DataFrame(data2) df = pd.concat([df1, df2], ignore_index=True) print(df) ``` 執行結果: ``` 商品 售價 折扣 0 計算機 200 0.9 1 剪刀 100 0.8 2 鉛筆 20 0.7 3 膠帶 40 0.9 4 修正液 110 0.8 ``` 說明: 1. 預設會連接兩個DataFrame的索引,`ignore_index`會重新給索引,從0開始。 2. `concat()`方法傳入的是一個清單,所以可以連接兩個以上的DataFrame。 #### 合併(merge) 將有不同欄位的DataFrame合併再一起。 ``` import pandas as pd data1 = { '商品': ['計算機', '剪刀', '鉛筆', '修正液'], '售價': [200, 100, 20, 30], '折扣': [0.9, 0.8, 0.7, 0.8] } df1 = pd.DataFrame(data1) df1.index = ['A', 'B', 'C', 'D'] data2 = { '庫存': [10, 20, 30] } df2 = pd.DataFrame(data2) df2.index = ['A', 'B', 'D'] df = pd.merge(df1, df2, left_index=True, right_index=True, how='left') print(df) ``` 執行結果: ``` 商品 售價 折扣 庫存 A 計算機 200 0.9 10.0 B 剪刀 100 0.8 20.0 C 鉛筆 20 0.7 NaN D 修正液 30 0.8 30.0 ``` ##### 參數說明: - `on`:要使用哪一個欄位作為主鍵,如果沒有指定該參數,則預設會有重複欄位名稱的值都要相同才會被合併 - `left_index`、`right_index`:是否要使用索引值當作主鍵 - `how`:要保留哪一邊的資料,沒有可以合併的欄位,會填入`NaN`,有`inner`(交集)、`outer`(聯集)、`left`、`right`,預設為`inner`` - `lefton`、`righton`:當出現欄位資料一樣,但是欄位名不一樣,可以指定左右兩個Dataframe要使用的主鍵名稱。 - `suffixes`:當左右兩個表出現相同欄位名的時候,要如何顯示後綴,預設為`_x`和`_y` - `indicator`:合併後的表格最後面會多一欄紀錄該筆資料是來自哪一張表格,兩張表格都有,會標記為`both` #### 分群(groupie) ##### 計算加總 ``` data = { '日期':['2021-01-01','2021-01-02','2021-01-01','2021-01-03','2021-01-04','2021-01-04','2021-01-01'], '消費':[100, 250, 50, 75, 80, 10, 65] } df = pd.DataFrame(data) df_sum = df.groupby('日期').sum() print(df_sum) ``` 執行結果: ``` 日期 消費 2021-01-01 215 2021-01-02 250 2021-01-03 75 2021-01-04 90 ``` > **補充** > > `df.groupby('日期').sum()`也可以寫成`df.groupby('日期').apply(sum)` ##### 計算平均 ``` data = { '日期':['2021-01-01','2021-01-02','2021-01-01','2021-01-03','2021-01-04','2021-01-04','2021-01-01'], '消費':[100, 250, 50, 75, 80, 10, 65] } df = pd.DataFrame(data) df_sum = df.groupby('日期').mean().astype(int) print(df_sum) ``` 執行結果: ``` 日期 消費 2021-01-01 71 2021-01-02 250 2021-01-03 75 2021-01-04 45 ``` > `astype(int)`是為了去掉小數點,或是可以改為`round(0)`做四捨五入。 ##### 處理多個指定的欄位 你也可以在groupby()方法後面透過索引的方式來指定處理的欄位,如果有多個欄位則需使用list存放多個欄位的名稱,例如: ``` data = { '日期':['2021-01-01','2021-01-02','2021-01-01','2021-01-03','2021-01-04','2021-01-04','2021-01-01'], '交通':[100, 250, 50, 75, 80, 10, 65], '飲食':[1200, 2250, 520, 725, 820, 120, 625], '門票':[1010, 2150, 510, 175, 180, 130, 635], '購物':[1000, 1250, 150, 715, 810, 110, 615] } df = pd.DataFrame(data) df_sum = df.groupby('日期')[['交通', '飲食']].sum() print(df_sum) ``` > **補充** > > 在Pandas1.0.0以後,如果要加總多個欄位,在索引的地方直接使用多個索引(`['交通', '飲食']`),而沒有使用list,會出現下面警告: > > ``` > /usr/local/lib/python3.7/dist-packages/ipykernel_launcher.py:17: FutureWarning: Indexing with multiple keys (implicitly converted to a tuple of keys) will be deprecated, use a list instead. > ``` > > 所以需要將多個欄位名稱使用list來存放: > > ``` > ['交通', '飲食'] > ``` > > 改為: > > ``` > [['交通', '飲食']] > ``` #### 套用(apply) 透過`apply()`方法可呼叫我們自訂的函式還處理每個欄位資料。 ``` data = { '欄位1': [1, 2, 3, 4, 5, 6], '欄位2': ['A', 'B', 'C', 'D', 'E', 'F'] } df = pd.DataFrame(data) def plus10(val): return val + 10 s_result = df['欄位1'].apply(plus10) print(s_result) ``` 執行結果: ``` 0 11 1 12 2 13 3 14 4 15 5 16 Name: 欄位1, dtype: int64 ``` 說明: `apply()`後回傳為一個Series。 ## 其他 #### 將大DataFrame依照指定的數量切割成更小的DataFrame ``` size = 5 # 要切割的大小 df_list = [df.iloc[i:i+size,:] for i in range(0, len(df), size)] group_size = 5 # 要分組的大小 df_list_group = [df_list[i:i+group_size] for i in range(0, len(df_list), group_size)] print('DataFrame總數:', len(df)) print('DataFrame分組:', len(df_list)) print('分組後的分群:', len(df_list_group)) ``` ## 實戰範例 下面有一個公司人事資料的excel: > **備註:** > > 如果沒有該檔案,可以先用下面程式碼產生excel檔案。 ``` from cmath import nan from statistics import mean import pandas as pd data = { '員工編號':['0001','0002','0003','0004','0005','0006','0007','0008','0009','0010'], '姓名':['Aaron', 'Andy', 'Apple', 'Amber', 'Abner', 'Ann', 'Amonda', 'Alber', 'Ace', 'Alan'], '部門':['人事部', '研發一部', '業務處', '業務處', '研發二部', '研發二部', '產品處', '產品處', '技術服務處', '產品處'], '年資':[5, 20, 10, 3, 18, 3, 7, 1, 14, 6], '職等':['A1', 'B2', 'C3', 'D2', 'A5', 'A3', 'B1', 'C1', 'D5', 'B5'], # A~E職等, 每個職等有1~5級, 越大數字職位越高 '薪資':[30000, 45000, 80000, 120000, 35000, 33000, 60000, 95000, 150000, 75000], '109年考績':['A', 'B', 'C', 'A', 'A', 'B', 'A', 'B', 'C', 'A'], # 分為A+, A, A-, B+, B, B-, C+, C, C- '110年考績':['A', 'A', 'C', 'B', 'A', 'B', 'A', 'B', 'C', 'A'], '111年考績':['A', 'B', 'C', 'A', 'A', 'B', 'A', 'B', 'B', 'A'] } pd.DataFrame(data).to_excel('XX公司年度考績表.xlsx') # 建立Excel檔 ``` #### 調薪 111年度公司預計依據年資來幫員工調薪,條件為: - 年資1~5年調整3% - 6~10年5% - 10~15年7% - 20年以上10% 計算調薪後薪水為: ``` df = pd.read_excel('XX公司年度考績表.xlsx') # 讀取excel df['調薪後'] = nan print(df) def salary(val1): newSalary = 0 if(val1['年資'] <= 5): newSalary = val1['薪資'] * 1.03 elif(val1['年資'] <= 10): newSalary = val1['薪資'] * 1.05 elif(val1['年資'] <= 15): newSalary = val1['薪資'] * 1.07 else: newSalary = val1['薪資'] * 1.1 val1['調薪後'] = int(newSalary) return val1 df = df.apply(salary, axis=1) print(df) ``` #### 將各等級考績的員工分群並列出姓名 ``` # 取得各考績名單與人數 g = df.groupby('111年考績')[['姓名','部門']] print(list(g.get_group('A')['姓名'])) # 各考績人數 print(df.groupby('111年考績')['姓名'].count()) ``` #### 計算各部門總人事費用和平均薪資 ``` print(df.groupby('部門')[['薪資', '調薪後']].agg('sum')) print(df.groupby('部門')['薪資'].agg(lambda val: int(mean(val)))) ``` #### Aggregation可以套用的函式 |Aggregation| Description| |--|--| |count()| 聚合的元素數量 | |first(), last() |第一個和最後一個元素| |mean(), median() |Mean and median| |min(), max() |Minimum and maximum| |std(), var()| Standard deviation and variance| |mad()| Mean absolute deviation| |prod() |Product of all items| |sum() |Sum of all items| ``` ```