我正在处理一个看起来像这样的数据集:
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
这是一个相当复杂的问题,我无法解决。如果有人对此提供帮助,我们将不胜感激。
答案 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
中来回移动以选择比率所需的其他值。 (在函数开始时,索引被转换为标准索引,只是为了确定,因为我希望能够在其上使用 +/-
。)