2017-09-02 151 views
0

我的熊貓數據框如下:熊貓透視表

df = pd.DataFrame({"PAR NAME":['abc','def','def','def','abc'], "value":[1,2,3,4,5],"DESTCD":['E','N','E','E','S']}) 

我需要轉動自由度的PAR名稱,並找出它的價值%年齡來自哪裏DESTCD是「E」的地方。像這樣的東西(這顯然沒有工作!)

df.pivot_table(index="PAR NAME",values=["value"],aggfunc={'value':lambda x: (x.sum() if x["DESTCD"]=="E")*100.0/x.sum()}) 

我目前做這通過增加一個條件列,然後總結其與支點「價值」一起,然後分,但我的數據庫是巨大的(1GB +)而且必須有一個更簡單的方法。

編輯:預期輸出 ABC 16.67(因爲ABC以及E是1出總ABC它是6) DEF 77.78(因爲DEF和E是7出的總共9個DEF的);

(注:請不要推薦切片多dataframes提到我的數據是巨大的,效率很關鍵,:))

+1

您可以添加預期的輸出 – Dark

回答

1

我試圖解決這個問題沒有明確提到 'E' 所以它推廣到任何字母開頭。輸出是一個數據框,然後您可以在E上索引以獲得答案。我簡單地分別進行了聚合,然後使用了高效的連接方法。

df = pd.DataFrame({"PAR NAME":['abc','def','def','def','abc'], "value":[1,2,3,4,5],"DESTCD":['E','N','E','E','S']}) 

# First groupby 'DESTCD' and 'PAR NAME' 
gb = df.groupby(['DESTCD', 'PAR NAME'], as_index=False).sum() 
print(gb) 
    DESTCD PAR NAME value 
0  E  abc  1 
1  E  def  7 
2  N  def  2 
3  S  abc  5 

gb_parname = gb.groupby(['PAR NAME']).sum() 
out = gb.join(gb_parname, on='PAR NAME', rsuffix='Total') 
print(out) 
    DESTCD PAR NAME value valueTotal 
0  E  abc  1   6 
1  E  def  7   9 
2  N  def  2   9 
3  S  abc  5   6 

out.loc[:, 'derived']= out.apply(lambda df: df.value/df.valueTotal, axis=1) 

print(out) 
    DESTCD PAR NAME value valueTotal derived 
0  E  abc  1   6 0.166667 
1  E  def  7   9 0.777778 
2  N  def  2   9 0.222222 
3  S  abc  5   6 0.833333 

這也是一個比較有效的操作

%%timeit 
gb = df.groupby(['DESTCD', 'PAR NAME'], as_index=False).sum() 
gb_parname = gb.groupby(['PAR NAME']).sum() 
out = gb.join(gb_parname, on='PAR NAME', rsuffix='Total') 
out.loc[:, 'derived']= out.apply(lambda df: df.value/df.valueTotal, axis=1) 
100 loops, best of 3: 6.31 ms per loop 
+0

你能解釋爲什麼嗎?當我將這個條件添加到頂端,並且將它與您的時間相比時,它似乎幾乎相同(11.2毫秒vs 10毫秒)。據我所知,我使用的操作通常是高效的。所有的計算都是goupbys,連接和應用。我認爲沒有理由期待這個速度非常緩慢 - 我也沒有看到它的時間。儘管我願意被證明是錯誤的,並且如果我錯過了某些東西,我會感興趣。 –

+0

通常我不喜歡「應用」它有時會殺死性能。而OP只想在DESTCD =='E''行上執行操作。添加新列不是必需的。你的解決方案也很好。時間也取決於機器。我的機器需要1.2秒的解決方案。 – Dark

+0

謝謝!我用了一些修改來允許不同的aggs用於其他cols,比如val2: gb = df。groupby(['DESTCD','PAR NAME'],as_index = False).agg({'value':sum,'value2':lambda x:len(x)}) gb_parname = gb.groupby NAME'])['value']。sum() out = gb.join(gb_parname,on ='PAR NAME',rsuffix ='Total') out.loc [:,'derived'] = out.apply (lambda df:df.value * 100.0/df.valueTotal,axis = 1) out [out [「DESTCD」] =='E'] –

1

相反的數據透視表,你可以使用基於PAR NAME多個GROUPBY方法,然後應用操作你要。即

new = df[df['DESTCD']=='E'].groupby('PAR NAME')['value'].sum()*100/df.groupby('PAR NAME')['value'].sum() 

輸出:

 
PAR NAME 
abc 16.666667 
def 77.777778 
Name: value, dtype: float64 

如果想定時

%%timeit 

df[df['DESTCD']=='E'].groupby('PAR NAME')['value'].sum()*100/df.groupby('PAR NAME')['value'].sum() 
100 loops, best of 3: 4.03 ms per loop 

%%timeit 
df = pd.concat([df]*10000) 
df[df['DESTCD']=='E'].groupby('PAR NAME')['value'].sum()*100/df.groupby('PAR NAME')['value'].sum() 

100 loops, best of 3: 15.6 ms per loop 
+0

謝謝!這是一個同樣好的解決方案,符合我的目的;我選擇了正確的答案,只是基於我的電腦上精確的更快的速度 –

0

我還發現了一種通過旋轉來回答這個問題是因爲選擇的答案同樣有效!添加在這裏爲他人方便:

df.pivot_table(index="PAR NAME",values=["value"],aggfunc={'value':lambda x: x[df.iloc[x.index]['DESTCD']=='E'].sum()*100.0/x.sum()}) 

邏輯在於aggfunc只與系列作品中的問題,不能引用任何其他系列,直到你通過索引的主要DF得到他們。