GroupBy Pandas with ratio

时间:2021-07-13 07:30:56

标签: python pandas dataframe numpy

我正在处理一个看起来像这样的数据集:

ID  Amount Type
1   50    A
1   1000  A
1   500   B
1   200   B
2   1000  A
2   500   B

我正在尝试做两件事:找到每种类型的最长序列的长度,并为每个 ID 找到这些序列的 A/B 和 B/A 比率。

Ratio 属性说明:计算每个 ID 在最长序列中的总量(比如长度 n)。如果序列是类型A的序列,则得到与类型B的直接数量的比率(n+1数量)。如果序列是类型 B,则得到与类型 A 的直接前辈的比率(n-1 数量)。

所以在我提到的情况下,最终结果如下:

ID Longest_Sequence_A Longest_Sequence_B Ratio_A_B  Ratio B_A
1  2                  2                  0.47        0.7
2  1                  1                  0.5         0.5

第 1 行的解释:最长序列只是类型 A 和类型 B 的最长序列的长度。
对于比率A_B:这是前面定义的情况1,因此计算最长序列中所有类型A的总和(1050),然后与直接连续的B类型量(500)取比率,比率500 /1050=0.47
对于比率B_A:这是前面定义的情况2,因此计算最长序列中所有类型B的总和(700),然后与类型A的直接前驱量(1000)取比率, 比率 700/1000=0.7

这是一个相当复杂的问题,我无法解决。如果有人对此提供帮助,我们将不胜感激。

1 个答案:

答案 0 :(得分:2)

这是一个尝试:

def ratios(df):
    df = df.reset_index(drop=True)
    groups = (df.Type != df.Type.shift(1)).cumsum()
    result = {}
    for t in ('A', 'B'):
        if t in df.Type.values:
            max_num = groups[df.Type.eq(t)].mode().iat[-1]
            max_group = df[groups.eq(max_num)]
            result[f'Longest_Sequence_{t}'] = len(max_group)
            amounts = max_group.Amount.sum()
            idx = max_group.index
            ratio = None
            if t == 'A':
                if idx[-1] != df.index[-1] and amounts != 0:
                    ratio = df.Amount.at[idx[-1] + 1] / amounts
            elif t == 'B':
                if idx[0] != df.index[0]:
                    denom = df.Amount.at[idx[0] - 1]
                    if denom != 0:
                        ratio = amounts / denom
            result[f'Ratio_{t}'] = ratio
        else:
            result[f'Longest_Sequence_{t}'] = 0
            result[f'Ratio_{t}'] = None
    return pd.DataFrame([result])

df = df.groupby('ID').apply(ratios).reset_index(level=1, drop=True)

数据框的结果

   ID  Amount Type
0   1      50    A
1   1    1000    A
2   1     500    B
3   1     200    B
4   2    1000    A
5   2     500    B

    Longest_Sequence_A  Ratio_A  Longest_Sequence_B  Ratio_B
ID                                                          
1                    2  0.47619                   2      0.7
2                    1  0.50000                   1      0.5

列的命名和排序略有不同,但这应该无关紧要。


一些解释(我使用整个数据框作为示例):

groups = (df.Type != df.Type.shift(1)).cumsum() 标识序列:

0    1
1    1
2    2
3    2
4    3
5    4
Name: Type, dtype: int64

对于groups[df.Type.eq('A')]

0    1
1    1
4    3
Name: Type, dtype: int64

.mode() 标识最大长度序列的 'A'-序列号(如果存在相同长度的最大序列,.iat[-1] 选择最后一个):

0    1
dtype: int64

现在用 max_num == 1 这个 max_group = df[groups.eq(max_num)] 选择索引来自 df 的相应组(最后一点对其余部分很重要):

   ID  Amount Type
0   1      50    A
1   1    1000    A

剩下的就是尝试按照您的计算说明进行操作,从而处理边缘情况。使用相对于 idx 的索引 df 允许在 df 中来回移动以选择比率所需的其他值。 (在函数开始时,索引被转换为标准索引,只是为了确定,因为我希望能够在其上使用 +/-。)

相关问题