Manipulating DataFrames with pandas — Not Weird Part 在操作中的一些小細節

學.誌|Chris Kang
不止數據|Not Only Data
11 min readNov 12, 2019

--

Photo from Unsplash

DataFrame 的操作對於資料分析的重要,就像吃牛排對於刀叉的關係。但目前在操作上,仍然必須要 Case by Case 來解析使用,因此目前會比較偏向筆記性質, 之後還會慢慢繼續更新。

更動 DataFrame 與 Series 的「 index 與 columns name」:

不僅僅只有 indexname 的屬性,連 columns 也有!而且 DataFrameindex 是 immutable,因此一但需要更改就必須要整個 index series 一起更動。

# Assign the string 'MONTHS' to sales.index.name
sales.index.name = 'MONTHS'
# Print the sales DataFrame
print(sales)
# Assign the string 'PRODUCTS' to sales.columns.name
sales.columns.name = 'PRODUCTS'
# Print the sales dataframe again
print(sales)
## OUTPUT:PRODUCTS eggs salt spam # PRODUCTS 就是columns 的 name
MONTHS
JAN 47 12.0 17
FEB 110 50.0 31
MAR 221 89.0 72
APR 77 87.0 20
MAY 132 NaN 52
JUN 205 60.0 55

DataFrame Single Index 最常使用的篩選方式

首先先設定條件,使該變數成為一個轉換為布林值的 Series。之後再把這個 Series 放入 [] 裡進行篩選,就能夠把條件為 True 的資料列印出來。

# Create the boolean array: high_turnout
high_turnout = election['turnout'] > 70
# Filter the election DataFrame with the high_turnout array: high_turnout_df
high_turnout_df = election[high_turnout]
# Print the high_turnout_results DataFrame
print(high_turnout_df)

如果我們想要把含有缺值的資料刪除,則可以簡單的使用 dropna()。如果我們在檢驗資料的過程,發現整列都是無用的數據,則可使用 drop()

在使用上 drop 可以輸入參數 drop(‘n_col’, axis=’columns’, inplace=True),代表要把 n_col 整列刪除,inplace 則是真實從數據中刪除。

dropna 則的用法則為 dropna(subset=[‘stop_date’, ‘stop_time’], inplace=True) ,大致上方法與 drop 都一樣。

# Select the 'age' and 'cabin' columns: df
df = titanic.loc[:, ['age', 'cabin']]
# Print the shape of df
print(df.shape)
# Drop rows in df with how='any' and print the shape
print(df.dropna(how='any').shape)
# Drop rows in df with how='all' and print the shape
print(df.dropna(how='all').shape)

如果不僅如此,我們還想要把資料量不夠的欄位刪除,那這時就可以使用 dropna() 的 thresh 的參數(只要低於這個數量就會被剔除)啦。

通常情况下删除行,使用參數 axis = 0;刪除列的參數則為 axis = 1,通常不會這麼做,那樣會删除一個變量。

# Drop columns in titanic with less than 1000 non-missing values
print(titanic.dropna(thresh=1000, axis='columns').info())

如果相反,想要替換調缺失值,則可以用 fillna(裡面塞想要替換的數值)。

如果有資料不屑用(或是不能用),可以手工塞入 NaN

利用篩選出的 Series 後,塞入 np.nan 來替換成 NaN 避免程式計算進去。

# Import numpy
import numpy as np
# Create the boolean array: too_close
too_close = election['margin'] < 1
# Assign np.nan to the 'winner' column where the results were too close to call
election.winner[too_close] = np.nan
# Print the output of election.info()
print(election.info())

用 Apply 與 Map 以 function 替換 dataFrame 裡面的資料:

條件一:如果所有要調整的數據方式都一樣,就可以用 apply 來應用。

首先先寫一個想要替換的 function,之後選定想要調整的 dataFrame 後,對該欄位直接使用 function,記得 function 後面不用加小括號

# Write a function to convert degrees Fahrenheit to degrees Celsius: to_celsius
def to_celsius(F):
return 5/9*(F - 32)
# Apply the function over 'Mean TemperatureF' and 'Mean Dew PointF': df_celsius
df_celsius = weather.loc[:,['Mean TemperatureF','Mean Dew PointF']].apply(to_celsius)
# Reassign the column labels of df_celsius
df_celsius.columns = ['Mean TemperatureC', 'Mean Dew PointC']
# Print the output of df_celsius.head()
print(df_celsius.head())

條件二:如果是要根據已經有的條件映射出新的一欄,則用 map 來操作

首先先寫一個 Dict 來放置規則,之後找出要篩選的欄位並使用 map 方法,就可以根據 Dict 設定的條件,映射出新的一個欄位。

# Create the dictionary: red_vs_blue
red_vs_blue = {'Obama':'blue', 'Romney':'red'}
# Use the dictionary to map the 'winner' column to the new column: election['color']
election['color'] = election['winner'].map(red_vs_blue)
# Print the output of election.head()
print(election.head())

條件三:如果數具有幾百萬條,瘋子才用 applymap

vectorized functions!You can loop over the data at the same speed as compiled code (C, Fortran, etc.)! NumPy, SciPy and pandas come with a variety of vectorized functions (called Universal Functions or UFuncs in NumPy)

下面就用 zscore 來演示一下如何應用:

# Import zscore from scipy.stats
from scipy.stats import zscore
# Call zscore with election['turnout'] as input: turnout_zscore
turnout_zscore = zscore(election['turnout'])
# Print the type of turnout_zscore
print(type(turnout_zscore))
# Assign turnout_zscore to a new column: election['turnout_zscore']
election['turnout_zscore'] = turnout_zscore
# Print the output of election.head()
print(election.head())

快速建立一個新的 index List

來用個快速的 List Comprehension 吧!首先把設定的變數後面加上方式,之後直接接上 for 回圈。

# Create the list of new indexes: new_idx
new_idx = [month.upper() for month in sales.index]
# Assign new_idx to sales.index
sales.index = new_idx
# Print the sales DataFrame
print(sales)

設定 MultiIndex 和排序它

設定就用一個簡單的 set_index() 就可以設定 MultiIndex 的兩個 Title。如果要根據新建之後的 index 來進行排序,則再使用 sort_index() 即可。

# Set the index to be the columns ['state', 'month']: sales
sales = sales.set_index(['state', 'month'])
# Sort the MultiIndex: sales
sales = sales.sort_index()
# Print the sales DataFrame
print(sales)

快速篩選 MultiIndex Using loc

如果要篩選 MultiIndex,需要輸入參數 tuple 來篩選,如果第一個列的參數沒有要使用,記得仍然要放入 slice(None) 來佔位。另外如果要篩選兩個以上的條件,就需要加上 slice(‘A’, ‘B’) 來進行篩選。

# Look up data for NY in month 1 in sales: NY_month1
NY_month1 = sales.loc[('NY', 1), :]
# Look up data for CA and TX in month 2: CA_TX_month2
CA_TX_month2 = sales.loc[(['CA', 'TX'], 2),:]
# Access the inner month index and look up data for all states in month 2: all_month2
all_month2 = sales.loc[(slice(None), 2), :]

計算資料欄位的不重複個數

當初知道有這個 method 的時候,真的不誇張我整個從電腦桌前跳起來。想當初我為了要計算各個用戶的購買頻率,用 Excel 處理九萬多筆資料…。所有的數據統計都是一種夢魘,沒想到在 Pandas 裡一個函式就解決,真的難以形容知道這個 method 時的震驚。

好正文開始,當我們想要計算該 DataFrame 不重複的個數共有多少時,我們就能直接使用 pd.DataFrame.nunique(),他就會計算出該列不重複的元素有幾個;相反地,如果是要取出不重複的值各有幾個,則可以使用 pd.DataFrame.unique() ,對就是少一個 n,你說這麼簡單,神不神奇?

當然,也能加入參數 axis = 0,10 or index 為計算行,1 or column 則為計算列;如果再設定 dropna = True 則可不列入計算 NaN 的值。

Series 也有同樣的參數,只是不能指定特定的欄位。

### DataFrame
>>> import pandas as pd
>>> df=pd.DataFrame({'A':[0,1,2],'B':[4,5,6]})
>>> df.nunique()
A 3
B 3
dtype: int64
>>> df=pd.DataFrame({'A':[0,1,1],'B':[0,5,6]})
>>> df.nunique()
A 2
B 3

DataFrame 後面也可使用 pd.value_counts(Series) method 來計算總數,這對已經篩選過的條件特別好用,能夠快速計算出該欄位個別的數量。如果要計算該欄位的數量則可用 count()。當然這裡也可以結合 groupby 的方式來使用,我會另外再開一篇解釋。

列出另外幾個對連續數值常用的計算值(對就是直覺上的功能),幫你快速計算該欄位的數值:

  • std()
  • mean()
  • min()
  • max()

PandasDataFrame 操作並不只有上述提到的這些,這是在課程與實際操作時會遇到的狀況,後續仍然會繼續補充,讓這個補充集能夠更完整。

參考資料:

--

--

學.誌|Chris Kang
不止數據|Not Only Data

嗨!我是 Chris,一位擁有技術背景的獵頭,熱愛解決生活與職涯上的挑戰。專注於產品管理/資料科學/前端開發 / 人生成長,在這條路上,歡迎你找我一起聊聊。歡迎來信合作和交流: chriskang0917@gmail.com