根据列值之间的差距对数据框进行分组

Grouping dataframe based on a gap between column values

假设我们有以下数据集:

Name    Num

First    1
Second   50
Third    110
Fourth   2
Fifth    58
Sixth    105
Seventh  8

我想根据 num 列的每一行之间的最大间隙(例如)10 对数据帧进行分组。因此,例如,我想要:

Name                   Num
First,Fourth,Seventh   1,2,8
Second,Fifth           50,58
Sixth,Third            105,110

我尝试使用 Raymond Hettinger's Answer,但我需要对数据框进行分组,而不仅仅是列,因为我想在之后做一个条形图。 我试过这个(我首先根据列对数据框进行排序):

    for idx,val in enumerate(df_sorted['num'], start=1):
    if idx == 1:
        groups =[df_sorted.iloc[idx]]
    elif abs(data['pos'][idx] - data['pos'][idx-1]) <= 10:
        groups[-1].append(data.iloc[idx,:])
    else:
        groups.append(data.iloc[idx,:])

但是我在理解列表在 Python 中的工作方式时遇到了一些问题(我一直在 R 中使用它们)。 不知道是否有更简单的方法使用 groupby 或其他方法(例如 Grouper 用于时间序列)。

编辑: 最后,我选择了以下方法来解决问题,使用 Raymond Hettinger 的答案:

def cluster(data, maxgap, column):
'''Arrange data into groups where successive elements
   differ by no more than *maxgap*
'''
#data.sort() #sort data if necessary
groups = list()
groups = [[data.iloc[0,:]]]

for idx,val in enumerate(data[column]):
    if idx > 0:
        if abs(val - data[column][idx-1]) <= maxgap:
            groups[-1].append(data.iloc[idx,:])
        else:
            groups.append([data.iloc[idx,:]])
return groups

我们将数字分箱以计算分布,然后根据该分布对它们进行分组和列出; N=24 是有意根据您的预期结果量身定制的。实际操作的阈值可能更难设置。例如,对于每 10 个类别,50 和 58 将是不同的组。

import pandas as pd
import numpy as np
import io

data = '''
Name Num
First 1
Second 50
Third 110
Fourth 2
Fifth 58
Sixth 105
Seventh 8
'''

df = pd.read_csv(io.StringIO(data), sep='\s+')

df.sort_values('Num', ascending=True, inplace=True, ignore_index=True)
N = 24
category = pd.cut(df['Num'], bins=np.arange(df['Num'].min(), df['Num'].max()+ N, N), right=False)

category.value_counts()
[1, 25)      3
[97, 121)    2
[49, 73)     2
[73, 97)     0
[25, 49)     0
Name: Num, dtype: int64

df.groupby(category).agg(list)
    Name    Num
Num     
[1, 25) [First, Fourth, Seventh]    [1, 2, 8]
[25, 49)    []  []
[49, 73)    [Second, Fifth] [50, 58]
[73, 97)    []  []
[97, 121)   [Sixth, Third]  [105, 110]