首页 > 解决方案 > 在 python 数据框中为重复项添加增量

问题描述

我正在寻找连接数据框中的两列,并且在有重复的地方,在末尾附加一个整数。这里的问题是我将继续接收数据源,并且增量需要了解生成的历史值而不是重用它们。

我一直在尝试使用 apply 函数来执行此操作,但是当单个接收到的数据集中有重复项时我遇到了问题,而且我无法在不遍历数据帧的情况下找到一种方法来执行此操作(这通常是不受欢迎的)。

我已经做到了这一点:

import pandas as pd

def gen_summary(color, car, blacklist):
    exists = True
    increment = 0
    summary = color + car
    while exists:
        if summary in blacklist:
            increment += 1
            summary = color + car + str(increment)  # Append increment if in burn list
        else:
            exists = False  # Exit this loop
    return summary


def main():
    blacklist = ['RedToyota', 'BlueVolkswagon', 'BlueVolkswagon1', 'BlueVolkswagon2']
    df = pd.DataFrame(
        {'color': ['Red', 'Blue', 'Blue', 'Green'],
         'car': ['Toyota', 'Volkswagon', 'Volkswagon', 'Hyundai'],
         'summary': ['', '', '', '']}
    )
    #print(df)
    df["summary"] = df.apply(lambda x: gen_summary(x['color'], x['car'], blacklist), axis=1)
    print(df)


if __name__ == "__main__":
    main()

输出:

   color         car          summary
0    Red      Toyota       RedToyota1
1   Blue  Volkswagon  BlueVolkswagon3
2   Blue  Volkswagon  BlueVolkswagon3
3  Green     Hyundai     GreenHyundai

请注意,之前的数据馈送中使用了 BlueVolkswagon1 和 BlueVolkswagon2,因此这里必须从 3 开始。真正的问题是,仅此数据集中有重复的 BlueVolkswagon 值,因此它不会正确递增并重复 BlueVolkswagon3,因为我无法在将函数应用于整个数据集的过程中更新历史记录。

是否有一些优雅的 pythonic 方法可以做到这一点,我无法绕开我的脑袋,或者这是一个迭代数据框确实有意义的场景?

标签: pythonpython-3.xpandasdataframe

解决方案


我不完全确定您想要实现什么,但您可以blacklist在此过程中进行更新。blacklist只是指向实际列表数据的指针。如果你通过在语句之前gen_summary添加稍微修改blacklist.append(summary)return

def gen_summary(color, car, blacklist):
    ...
            exists = False  # Exit this loop
    blacklist.append(summary)
    return summary

你会得到以下结果

   color         car          summary
0    Red      Toyota       RedToyota1
1   Blue  Volkswagon  BlueVolkswagon3
2   Blue  Volkswagon  BlueVolkswagon4
3  Green     Hyundai     GreenHyundai

分组会更有效率。这应该产生相同的结果:

def gen_summary(ser, blacklist):
    color_car = ser.iat[0]
    summary = color_car
    increment = 0
    exists = True
    while exists:
        if summary in blacklist:
            increment += 1
            summary = color_car + str(increment)  # Append increment if in burn list
        else:
            exists = False  # Exit this loop
    return ([color_car + ('' if increment == 0 else str(increment))]
            + [color_car + str(i + increment) for i in range(1, len(ser))])

df['summary'] = df['color'] + df['car']
df['summary'] = df.groupby(['color', 'car']).transform(gen_summary, blacklist)

这就是你要找的结果吗?如果是,我想添加一个优化您的方法的建议:使用字典而不是列表blacklist

def gen_summary(color, car, blacklist):
    key = color + car
    num = blacklist.get(key, -1) + 1
    blacklist[key] = num
    return key if num == 0 else f'{key}{num}'

blacklist = {'RedToyota': 0, 'BlueVolkswagon': 2}

或分组

def gen_summary(ser, blacklist):
    key = ser.iat[0]
    num = blacklist.get(key, -1) + 1
    return ([f'{key}{"" if num == 0 else num}']
            + [f'{key}{i + num}' for i in range(1, len(ser))])

blacklist = {'RedToyota': 0, 'BlueVolkswagon': 2}
df['summary'] = df['color'] + df['car']
df['summary'] = df.groupby(['color', 'car']).transform(gen_summary, blacklist)

while如果没有-loop 和更快的查找,应该会产生相同的结果。


推荐阅读