# 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|
```
```