给定此数据框架:
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
您可能已经推测,这里的第一个问题是它将lambda函数应用于"最终"分数的整列,而不仅仅是属于组中每个组的分数。第二个问题是我需要一列指定正确的组(类(会员资格,大概是通过使用变换而不是应用。
。我尝试了以下方法:
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
此返回:
组边界列表
与"最终"的值相关的上边界
与"最终"的值相关的下边界
根据评论中指出的"最终"值属于的值。
您的 jenks
在 x
(即lambda变量(方面定义为常数,因此它不取决于用 apply
或 transform
喂食它。将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
当前,您将系列传递到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)