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物件

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

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_indexright_index:是否要使用索引值當作主鍵
  • how:要保留哪一邊的資料,沒有可以合併的欄位,會填入NaN,有inner(交集)、outer(聯集)、leftright,預設為`inner``
  • leftonrighton:當出現欄位資料一樣,但是欄位名不一樣,可以指定左右兩個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