【问题标题】:Pandas Groupby with Lambda and AlgorithmPandas Groupby 与 Lambda 和算法
【发布时间】:2023-03-23 14:46:01
【问题描述】:

给定这个数据框:

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”中的“Final”中的每个值都属于这些组。

我是这样开始的:

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 函数应用于“最终”分数的整个列,而不仅仅是属于 Groupby 中每个组的分数。第二个问题是我需要一个列来指定正确的组(类)成员资格,大概是使用转换而不是应用。

然后我尝试了这个:

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

更新:

这是想要的结果。 “Result”列包含每个组“BreakGroup”的“Final”中相应值的组上限:

    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. 与“Final”值相关的下边界

  4. 根据 cmets 中记录的逻辑,“Final”值所属的组。

【问题讨论】:

  • 你能发布目标输出吗?
  • 当然;查看更新。

标签: python pandas lambda group-by


【解决方案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)

【讨论】:

    【解决方案2】:

    您已将jenks 定义为一个常量,它是根据您的 lambda 变量 x 定义的,因此它不依赖于您使用 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
    

    【讨论】:

    • 太棒了!顺便说一句,我用它来获得下限值: group2= lambda x: [gp for gp in x['Groups'] if gp
    • @DanceParty2 因为您使用的是&lt;=,而不是&lt;,所以您不需要or gp == min(x['Groups']) 子句,其等效项仅存在于原版中以避免尝试从空列表中拉出一个元素。
    • 如何查找值的索引而不是值本身(即顶行为 0)?
    • 你是说jenks产生的组列表中的哪个索引?
    • 是的,g的给定行的列表中元素的索引。
    猜你喜欢
    • 2019-02-15
    • 1970-01-01
    • 2020-11-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-05-13
    • 2020-04-18
    • 2021-07-14
    相关资源
    最近更新 更多