Photo by Michael Payne on Unsplash

使用 Pandas DataFrame 常用的 27 個基本技巧

Eric Tsai

--

本篇文章主要分四個部分,第一個部分是 dataframe 的基本操作,第二是過濾資料或找特定資料的方法,第三是 dataframe 資料分組的操作,最後一個部分則是我個人常用到的資料處理技巧

Dataframe 的基本操作

  1. 在本地主機載入和儲存 dataframe
import pandas# csv
df = pd.read_csv('./file_name.csv')
# json
df = pd.read_json ('./file_name.json')
# pikle
df = pd.read_pickle('./file_name.pkl')
# excel
df = pd.read_excel('./file_name.xlsx', sheet_name='sheet_name_1')

2. 從SQL Server 載入 dataframe

import pyodbccnxn = pyodbc.connect('Trusted_Connection=yes', driver='{SQL Server}', server='tcp:myserver')
cursor = cnxn.cursor()
sql = f'''
sql code here
'''
df = pd.read_sql(sql, cnxn)
cursor.close()
cnxn.close()

3. 將 data frame 輸出到本地主機

# csv
df.to_csv('./file_name.csv')
# json
df.to_json('./file_name.json')
# pikle
df.to_pickle('./file_name.pkl')
# excel
df.to_excel("file_name.xlsx", sheet_name='Sheet_name_1')

4. 手動建立 data frame

分別有兩種方法,一種是用矩陣表達資料樣式,另一種是用字典方式將資料轉換成 data frame

# create dataframe by matrix
data = [[1,2,3],
[4,5,6],
[7,8,9]]
pd.DataFrame(data, columns=['A','b','c'])
# create dataframe by dictionary
dic = {'A':[1,4,7],
'b':[2,5,8],
'c':[3,6,9]}
pd.DataFrame(dic)

5. 檢查 data frame 的資料

通常都是檢查前五列或後五列,展示的列數可以在括號內做調整

df.head()
df.tail()

6. data frame 重新命名

df.columns = ['name1', 'name2', 'name3']

7. 將特定欄位作為 data frame 的 index

df.set_index('A',inplace=True)

8. 透過特定欄位來合併兩個 data frame

df1 和 df2 都為 dataframe,how 為 data frame 合併的方式,比較常用的參數有 'inner' 、' left' 和 'right',如果熟悉 SQL 的人,這些合併方法應該不陌生,至於 left_on 和 right_on 則是合併兩個 data frame 所需要的 key 值

df1.merge(df2, how, left_on, right_on)

9. 串聯兩個 data frame

df3 = pd.concat([df1,df2], axis=1)

10. 重置 data frame 的 index,

data frame 的資料經過篩選後,index 會有跳號的情形,通常我們會透過下面的方法,重置 index

new_df = df.reset_index(drop=True,inplace=False)

11. 新增欄位到 data frame

# 我習慣的做法(會新增欄位到最後一欄)
df['new_col_name'] = data
# 但有時候你希望新增的欄位在指定的順序位置(ex.新增到第一欄)
df.insert(loc=0, column=’new_col_name’, value=1)

過濾資料和找特定資料的方法

12. 過濾 data frame 的資料

# 你想要A欄位大於10的資料,寫法如下
df.query("A>10")
# 你想要A欄位大於10,且B欄位小於12的資料,寫法如下
df.query("A>10 & B<12")

13. 透過 boolean(布林) 值,作為篩選指標

# 只回傳 column_name 等於 1 的資料列
df[df['column_name']==1]
# 只回傳 column_name1 和 column_name2 不是空值的資料列
df[df['column_name1'].notnull() & df['column_name2'].notnull()]
# 只回傳 column_name 有在出現在列表中的資料列
value_list = [1,3,5,7,9]
mask = df['column_name'].isin(value_list)
df[mask]

14. 透過 index 或欄位名稱找到 data frame 中的資料

Table1
df.iat[1,2]
out: 20
df.at[3,'A']
out: 2
df.loc[[1,3],['B','C']]
df.iloc[[1,3],[1,2]]
out:
B C
---------
1 0 20
3 0 0

Data Frame 資料分組的操作

15. data frame 資料分組

Data Frame 可以透過一個或多個欄位中的值進行分組,以上面 Table1的資料為例,如果透過A欄位進行分組,而A欄位只有 0, 1, 2 三種值的話,透過 groupby 可以將 data frame 分成相應的三組資料

df_groupby_A = df.groupby('A')
df_groupby_AB = df.groupby(['A' ,'B'])
# 我個人很常會用到 groupby 加 size 回傳 groupby 後欄位中各個數值的資料數量
df.groupby('A').size()

16. 取得分組資料

# 取得 A 欄數值是1的資料(列)
df_group_A.get_group(1)

17. 透過特定欄位來聚合其他欄位的資料

無論是分組進行統計相關計算(平均數、標準差等)或將其他欄位的資料透過列表儲存在 cell 當中,都是非常實用的技巧

test_group = df.groupby('A').agg({'A':sum, 'B': list})
test_group.reset_index(drop=True)
Table2

18. 轉置 data frame

df.T
Table1
Table3

資料處理技巧

19. apply

透過 apply 可以利用 function 一列一列的進行資料處理。另外有一個叫 swifter 的套件可以在 apply 的基礎上直接使用。

df['column_name1'].apply(function, axis=0)
df[['column_name1', 'column_name2']].apply(function, axis=1)
# use swifter
df['column_name'].swifter.progress_bar(False).apply(function)

20. np.vectorize

用法上幾乎跟 apply 一樣,主要差別在於 np.vectorize 有透過 numpy 套件在運算效能上進行優化,所以如果你撰寫的 function 裡面有越多東西可以轉移到 numpy,你運算的速度就會越快,但如果沒有,直接用 apply 會是更好的方法,有興趣可以參考這裡

np.vectorize(function)(df['column_name1'])

21. 依序疊代 data frame 的 row

請注意: 這不是一個好的資料處理方法,特別是資料龐大的時候,如果你確定要這麼做,請先確保其它更快的解決方案你都嘗試過了

# 透過 enumerate 可以依序回傳疊代的index(疊代到第幾次)和資料列
for index, row in enumerate(df['A']):
print(f'index: {index}, row: {row}')
# 透過 iterrows 和 itertuples 依序還傳資料列
for index, row in df.iterrows():
print(row['A'], row['B'])
for row in df.itertuples(index=True, name='Pandas'):
print(row.A, row.B)

22. 將有NA 值的列或欄丟棄

# axis=0 丟棄列,axis=1 丟棄欄
df.dropna(axis=0,inplace=True)
# 丟棄特定欄位
df.dropna(subset=['column_name'])

23. 重塑 data frame

將資料重塑成兩欄

pd.DataFrame(df.values.reshape(-1,2), columns=['A','B'])
Original Table
Reshape Table

24. 資料排序

df.sort_values(by='A', ascending = False)

資料處理技巧-進階

25. 丟棄滿足欄位名稱特定條件的欄位

假設今天有一個 data frame,欄位名稱分別為A_TW、B、C,但我們不想要結尾有 TW 的欄位,我們可以透過建構一個丟棄列表(其中包含所有結尾為TW 的欄位名稱)

droplist = [i for i in df.columns if i.endswith('TW')]
df.drop(droplist, axis=1, inplace=True)

26. 如果你有讀取 excel(xlsx file) 的經驗,有時候會出現以下狀況,這時你可以透過filter,過濾掉你不需要的欄位,跟上一個技巧有異曲同工之妙

df.drop(df.filter(regex="Unname"),axis=1, inplace=True)

27. 如果您習慣用 daat frame 整理資料的話,有時候你會遇到一種現象,如下

Original Table

這時如果你想要將 prefer_thing 欄位資料展開,以下提供兩個 function 幫助你垂直或水平展開欄位:

垂直展開

def flattenColumn(df, column):
"""
column is a string of the column's name.
for each value of the column's element (which might be a list),
duplicate the rest of columns at the corresponding row with the (each) value.
"""
column_flat = pd.DataFrame(
[
[i, c_flattened]
for i, y in df[column].apply(list).iteritems()
for c_flattened in y
],
columns=['I', column]
)
column_flat = column_flat.set_index('I')
return (
df.drop(column, 1)
.merge(column_flat, left_index=True, right_index=True)
)
Flatten column

水平展開

df = pd.DataFrame([pd.Series(x) for x in df.prefer_thing])
df.columns = ['team_{}'.format(x+1) for x in df.columns]

謝謝大家😱!!

--

--