【问题标题】:Adding an increment to duplicates within a python dataframe在 python 数据框中为重复项添加增量
【发布时间】:2020-11-14 23:49:24
【问题描述】:

我希望连接数据框中的两列,如果有重复,则在末尾附加一个整数。这里的问题是我将继续接收数据源,增量需要了解生成的历史值,而不是重复使用它们。

我一直在尝试使用 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 方法可以做到这一点,我无法理解,或者这是一个迭代数据框确实有意义的场景?

【问题讨论】:

    标签: python python-3.x pandas dataframe


    【解决方案1】:

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

    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 和更快的查找应该会产生相同的结果。

    【讨论】:

    • 哇,我想我只是盯着这个太久了,不知怎的,我突然想到黑名单数据框是不可变的,不能在函数范围内修改。我想答案是。也感谢您的优化。仍在学习管理和操作数据结构的“正确”方法。
    猜你喜欢
    • 1970-01-01
    • 2021-12-31
    • 2016-05-24
    • 2018-10-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-10-29
    相关资源
    最近更新 更多