文章來源:Youssef Hosni
作為資料科學家,使用正確的工具和技術來最大限度地利用資料是很重要的。Pandas是資料操作、分析和視覺化的重要工具,有效地使用Pandas可能具有挑戰性,從使用向量化操作到利用內建函式,這些最佳實踐可以幫助資料科學家使用Pandas快速準確地分析和視覺化資料。
在本文中,我們將重點介紹在DataFrame上經常執行的兩個最常見的任務,特別是在資料科學專案的資料操作階段。這兩項任務是有效地選擇特定的和隨機的行和列,以及使用replace()函式使用列表和字典替換一個或多個值。
在本文中,我們將使用下面的資料集:
◾️ 撲克牌遊戲資料集
◾️ 嬰兒名字資料集
我們使用的第一個資料集是撲克牌遊戲資料集,如下所示。
poker_data = pd.read_csv('poker_hand.csv')
poker_data.head()
在每個回合中,每個玩家手裡有五張牌,每一張牌都有花色:紅心、方塊、梅花或黑桃,以及它的數字,範圍從1到13。該資料集由一個人可以擁有的五張卡片的每一種可能組合組成。
Sn:第n張牌的符號,其中:1(紅心),2(方塊),3(梅花),4(黑桃)
Rn:第n張牌的排名,其中:1(王牌),2–10,11(J),12(Q),13(K)
第二個資料集是流行的嬰兒名字資料集,其中包括2011年至2016年間最流行的新生兒名字:
names = pd.read_csv('Popular_Baby_Names.csv')
names.head()
該資料集還包括按年份、性別和種族劃分的美國最受歡迎的名字。例如,2011年,Chloe 這個名字在所有亞裔和太平洋島民女性新生兒中排名第二。
下面我們開始進入正題
為什麼需要高效的程式碼?
高效程式碼是指執行速度更快、計算容量更低的程式碼。在本文中,我們將使用time()函式來測量計算時間,我們透過在執行前和執行後獲取時間,然後計算其差值獲得程式碼的執行時間。下面是一個簡單的例子:
import time
# record time before execution
start_time = time.time()
# execute operation
result = 5 + 2
# record time after execution
end_time = time.time()
print("Result calculated in {} sec".format(end_time - start_time))
Result calculated in 6.890296936035156e-05 sec
讓我們看一個提高程式碼執行時間並降低計算時間複雜度的示例:我們將計算每個數字的平方,從0到100萬。首先,我們將使用列表推導式來執行此操作,然後使用for迴圈重複相同的過程。
首先使用列表推導式:
#using List comprehension
list_comp_start_time = time.time()
result = [i*i for i in range(0,1000000)]
list_comp_end_time = time.time()
print("Time using the list_comprehension: {} sec".format(list_comp_end_time -
list_comp_start_time))
Time using the list_comprehension: 0.3217921257019043 sec
使用for迴圈來執行相同的操作:
# Using For loop
for_loop_start_time= time.time()
result=[]
for i in range(0,1000000):
result.append(i*i)
for_loop_end_time= time.time()
print("Time using the for loop: {} sec".format(for_loop_end_time - for_loop_start_time))
Time using the for loop: 0.5098655223846436 sec
可以看到它們之間有很大的差異,我們可以用百分比來計算它們之間的差異:
list_comp_time = list_comp_end_time - list_comp_start_time
for_loop_time = for_loop_end_time - for_loop_start_time
print("Difference in time: {} %".format((for_loop_time - list_comp_time)/
list_comp_time*100))
Difference in time: 58.44561804379364 %
可以看到僅僅使用了不同的方法,但是在執行效率方面有了很大的不同。
使用.iloc[]和.loc[]選擇行和列
這裡我們將介紹如何使用.iloc[] & .loc[] pandas函式從資料中高效地定位和選擇行。我們將使用iloc[]作為索引號定位器,使用loc[]作為索引名定位器。
在下面的例子中,我們選擇撲克資料集的前500行。首先使用.loc[]函式,然後使用.iloc[]函式。
rows = range(0, 500)
# Time selecting rows using .loc[]
loc_start_time = time.time()
poker_data.loc[rows]
loc_end_time = time.time()
print("Time using .loc[] : {} sec".format(loc_end_time - loc_start_time))
Time using .loc[] : 0.005123138427734375 sec
rows = range(0, 500)
# Time selecting rows using .iloc[]
iloc_start_time = time.time()
poker_data.iloc[rows]
iloc_end_time = time.time()
print("Time using .iloc[]: {} sec".format(iloc_end_time - iloc_start_time))
Time using .iloc[]: 0.0004892349243164062 sec
loc_comp_time = loc_end_time - loc_start_time
iloc_comp_time = iloc_end_time - iloc_start_time
print("Difference in time: {} %".format((loc_comp_time - iloc_comp_time)/
iloc_comp_time*100))
Difference in time: 947.1734892787524 %
雖然這兩個方法使用的方式是相同的,但iloc[]的執行速度比loc[]快近70%。這是因為.iloc[]函式利用了索引的順序,索引已經排序因此速度更快。
我們還可以使用它們來選擇列,而不僅僅是行。在下一個示例中,我們將使用這兩種方法選擇前三列。
iloc_start_time = time.time()
poker_data.iloc[:,:3]
iloc_end_time = time.time()
print("Time using .iloc[]: {} sec".format(iloc_end_time - iloc_start_time))
Time using .iloc[]: 0.0002753734588623047 sec
names_start_time = time.time()
poker_data[['S1', 'R1', 'S2']]
names_end_time = time.time()
print("Time using selection by name: {} sec".format(names_end_time - names_start_time))
Time using selection by name: 0.0016252994537353516 sec
loc_comp_time = names_end_time - names_start_time
iloc_comp_time = iloc_end_time - iloc_start_time
print("Difference in time: {} %".format((loc_comp_time - iloc_comp_time)/
loc_comp_time*100))
Difference in time: 83.05706322429222 %
可以看到,使用.iloc[]進行列索引仍然要快80%。所以最好使用.iloc[],因為它更快,除非使用loc[]更容易按名稱選擇某些列。
替換DF中的值
替換DataFrame中的值是一項非常重要的任務,特別是在資料清理階段。
讓我們來看看之前載入的嬰兒名字資料集:
首先看看性別列:
names['Gender'].unique()
array([‘FEMALE’, ‘MALE’], dtype=object)
我們可以看到,女性用大寫和小寫兩個值表示。這在實際資料中非常常見,但是對於我們來說只需要一個統一的表示就可以了,所以我們需要將其中一個值替換為另一個值。這裡有兩種方法,第一種是簡單地定義我們想要替換的值,然後我們想用什麼替換它們。如下面的程式碼所示:
start_time = time.time()
names['Gender'].loc[names.Gender=='female'] = 'FEMALE'
end_time = time.time()
pandas_time = end_time - start_time
print("Replace values using .loc[]: {} sec".format(pandas_time))
Replace values using .loc[]: 0.002582073211669922 sec
第二種方法是使用panda的內建函式.replace(),如下所示:
start_time = time.time()
names['Gender'].replace('female', 'FEMALE', inplace=True)
end_time = time.time()
replace_time = end_time - start_time
print("Time using replace(): {} sec".format(replace_time))
Time using replace(): 0.0024094581604003906 sec
可以看到,與使用.loc()方法查詢值的行和列索引並替換它相比,內建函式的快了157%。
print('The differnce: {} %'.format((pandas_time- replace_time )/replace_time*100))print('The differnce: {} %'.format((pandas_time- replace_time )/replace_time*100))
The differnce: 7.164060953888779 %
我們還可以使用列表替換多個值。比如說將所有WHITE NON-HISPANIC或WHITE NON-HISP都改為WNH。這裡我們使用.loc[]函式和’ or ‘語句定位我們正在尋找的種族。然後進行替換賦值。
start_time = time.time()
names['Ethnicity'].loc[(names["Ethnicity"] == 'WHITE NON HISPANIC') |
(names["Ethnicity"] == 'WHITE NON HISP')] = 'WNH'
end_time = time.time()
pandas_time= end_time - start_time
print("Results from the above operation calculated in %s seconds" %(pandas_time))
Results from the above operation calculated in 0.010097742080688477 seconds
或者使用pandas內建.replace() 函式執行相同的操作,如下所示:
start_time = time.time()
names['Ethnicity'].replace(['WHITE NON HISPANIC','WHITE NON HISP'],
'WNH', inplace=True)
end_time = time.time()
replace_time = end_time - start_time
print("Time using .replace(): {} sec".format(replace_time))
Time using .replace(): 0.003354787826538086 sec
我們可以再次看到,使用.replace()方法比使用.loc[]方法快得多。為了更好地直觀地瞭解它有多快,讓我們執行下面的程式碼:
print('The differnce: {} %'.format((pandas_time- replace_time )/replace_time*100))
The differnce: 200.99495416104043 %
.replace()方法比使用.loc[]方法快87%。如果資料很大,需要大量的清理,它將有效的減少資料清理的計算時間,並使pandas程式碼更快。
最後,我們還可以使用字典替換DataFrame中的單個值和多個值。如果想在一個命令中使用多個替換函式,這將是非常有用的。
我們要用字典把每個男性的性別替換為BOY,把每個女性的性別替換為GIRL。
names = pd.read_csv('Popular_Baby_Names.csv')
start_time = time.time()
names['Gender'].replace({'MALE':'BOY', 'FEMALE':'GIRL', 'female': 'girl'}, inplace=True)
end_time = time.time()
dict_time = end_time - start_time
print("Time using .replace() with dictionary: {} sec".format(dict_time))
Time using .replace() with dictionary: 0.0034475326538085938 sec
names = pd.read_csv('Popular_Baby_Names.csv')
start_time = time.time()
names['Gender'].replace('MALE', 'BOY', inplace=True)
names['Gender'].replace('FEMALE', 'GIRL', inplace=True)
names['Gender'].replace('female', 'girl', inplace=True)
end_time = time.time()
list_time = end_time - start_time
print("Time using multiple .replace(): {} sec".format(list_time))
Time using multiple .replace(): 0.002288818359375 sec
比較這兩種方法,可以看到使用字典的執行速度快了大約22%。
使用字典可以替換幾個不同列上的相同值。我們想把所有種族分成三大類:黑人、亞洲人和白人。這裡的程式碼也非常簡單。使用巢狀字典:外來鍵是我們要替換值的列名。值是另一個字典,其中的鍵是要替換的字典。
start_time = time.time()
names.replace({'Ethnicity': {'ASIAN AND PACI': 'ASIAN', 'ASIAN AND PACIFIC ISLANDER': 'ASIAN',
'BLACK NON HISPANIC': 'BLACK', 'BLACK NON HISP': 'BLACK',
'WHITE NON HISPANIC': 'WHITE', 'WHITE NON HISP': 'WHITE'}})
print("Time using .replace() with dictionary: {} sec".format (time.time() - start_time))
Time using .replace() with dictionary: 0.011412620544433594 sec
總結
使用.iloc[]函式可以更快地選擇行和列並且它比loc[]要快,但是loc[] 提供了一些更方便的功能,如果速度不是優先考慮或者iloc[]實現的比較麻煩的話,再考慮使用loc[]。
使用內建的replace()函式比使用傳統方法快得多。
使用python字典替換多個值比使用列表更快。
文章來源:DeepHub IMBA
文章連結:https://mp.weixin.qq.com/s/3eLbpb2ONuj3_QZ5KCUidQ
※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※
我是「數據分析那些事」。常年分享數據分析乾貨,不定期分享好用的職場技能工具。各位也可以關注我的Facebook,按讚我的臉書並私訊「10」,送你十週入門數據分析電子書唷!期待你與我互動起來~
文章推薦
◆跟資料打交道的人都得會的這8種資料模型,滿足工作中95%的需求
回顧十週入門數據分析系列文:
關注數據君的臉書:
我是「數據分析那些事」。常年分享數據分析乾貨,不定期分享好用的職場技能工具。按贊我的臉書,會有豐富資料包贈送唷!