2017-05-30 109 views
2

鑑於這種數據幀:熊貓GROUPBY用Lambda和算法

import pandas as pd 
import jenkspy 
f = pd.DataFrame({'BreakGroup':['A','A','A','A','A','A','B','B','B','B','B'], 
       'Final':[1,2,3,4,5,6,10,20,30,40,50]}) 
    BreakGroup Final 
0   A  1 
1   A  2 
2   A  3 
3   A  4 
4   A  5 
5   A  6 
6   B  10 
7   B  20 
8   B  30 
9   B  40 
10  B  50 

我想使用jenkspy標識該組,基於天然場所爲4組(類),每個值,其在「最後「屬於組內」BreakGroup「。

我開始做這個:

jenks=lambda x: jenkspy.jenks_breaks(f['Final'].tolist(),nb_class=4) 
f['Group']=f.groupby(['BreakGroup'])['BreakGroup'].transform(jenks) 

...這會導致:

BreakGroup 
A [1.0, 10.0, 20.0, 30.0, 50.0] 
B [1.0, 10.0, 20.0, 30.0, 50.0] 
Name: BreakGroup, dtype: object 

第一個問題在這裏,因爲你可能已經猜到,是它適用的拉姆達功能分配到「最終」分數的整列,而不僅僅是屬於Groupby中的每個組的分數。第二個問題是我需要一個指定正確的組(成員)成員的列,大概是通過使用transform而不是apply。

然後我嘗試這樣做:

jenks=lambda x: jenkspy.jenks_breaks(f['Final'].loc[f['BreakGroup']==x].tolist(),nb_class=4) 
f['Group']=f.groupby(['BreakGroup'])['BreakGroup'].transform(jenks) 

...卻又馬上打回就範:

ValueError: Can only compare identically-labeled Series objects 

更新:

這裏是理想的結果。 「結果」列包含來自「最終」每個組「BreakGroup」的相應值的組的上限:

BreakGroup Final Result 
0    A  1 2 
1    A  2 3 
2    A  3 4 
3    A  4 4 
4    A  5 6 
5    A  6 6 
6    B  10 20 
7    B  20 30 
8    B  30 40 
9    B  40 50 
10   B  50 50 

在此先感謝!

f.sort_values('BreakGroup',inplace=True) 
f.reset_index(drop=True,inplace=True) 
jenks = lambda x: jenkspy.jenks_breaks(x['Final'].tolist(),nb_class=4) 
g = f.set_index('BreakGroup') 
g['Groups'] = f.groupby(['BreakGroup']).apply(jenks) 
g.reset_index(inplace=True) 
groups= lambda x: [gp for gp in x['Groups']] 
#'final' value should be > lower and <= upper 
upper = lambda x: [gp for gp in x['Groups'] if gp >= x['Final']][0] # or gp == max(x['Groups']) 
lower= lambda x: [gp for gp in x['Groups'] if gp < x['Final'] or gp == min(x['Groups'])][-1] 
GroupIndex= lambda x: [x['Groups'].index(gp) for gp in x['Groups'] if gp < x['Final'] or gp == min(x['Groups'])][-1] 
f['Groups']=g.apply(groups, axis=1) 
f['Upper'] = g.apply(upper, axis=1) 
f['Lower'] = g.apply(lower, axis=1) 
f['Group'] = g.apply(GroupIndex, axis=1) 
f['Group']=f['Group']+1 

這將返回:

我基於接受的解決方案略作修改應用

  1. 組邊界的列表

  2. 上邊界相關的該值「Final」

  3. 與「最終」值相關的下邊界

  4. 根據註釋中指出的邏輯,「最終」值所屬的組。

+0

你能後的目標輸出? – EFT

+0

當然可以;請參閱更新。 –

回答

3

你必須在x方面定義爲一個常數jenks,你的λ變量,所以它不依賴於你applytransform養活它。的jenks定義更改爲

jenks = lambda x: jenkspy.jenks_breaks(x['Final'].tolist(),nb_class=4) 

給出

In [315]: f.groupby(['BreakGroup']).apply(jenks) 
Out[315]: 
BreakGroup 
A   [1.0, 2.0, 3.0, 4.0, 6.0] 
B [10.0, 20.0, 30.0, 40.0, 50.0] 
dtype: object 

從這個重新定義繼續,

g = f.set_index('BreakGroup') 
g['Groups'] = f.groupby(['BreakGroup']).apply(jenks) 
g.reset_index(inplace=True) 
group = lambda x: [gp for gp in x['Groups'] if gp > x['Final'] or gp == max(x['Groups'])][0] 
f['Result'] = g.apply(group, axis=1) 

In [323]: f 
Out[323]: 
    BreakGroup Final Result 
0   A  1  2.0 
1   A  2  3.0 
2   A  3  4.0 
3   A  4  6.0 
4   A  5  6.0 
5   A  6  6.0 
6   B  10 20.0 
7   B  20 30.0 
8   B  30 40.0 
9   B  40 50.0 
10   B  50 50.0 
+1

太棒了!順便說一句,我用它來得到下限值:group2 = lambda x:[gp在x ['Groups'中]如果gp <= x ['Final']或gp == min(x ['Groups' '])] [ - 1] –

+1

@ DanceParty2既然你使用'<=',而不是'<',你不需要'或gp == min(x ['Groups'])'子句,它的等價物只在原文中存在,以避免試圖從空列表中拉出元素。 – EFT

+0

如何找到值的索引而不是值本身(即頂行的值爲0)? –

1

目前,您正在將一系列文件傳入transform(),而不是標量,因爲您打算使用過濾條件。考慮對第一個值進行索引,例如x.index[0],因爲groupby系列中的所有值都相同。你甚至可以運行min(x)max(x)

lambda x: jenkspy.jenks_breaks(f['Final'].loc[f['BreakGroup']==x.index[0]].tolist(), nb_class=4) 

f['Group'] = f.groupby(['BreakGroup'])['BreakGroup'].transform(jenks)