【问题标题】:Replacing more than n consecutive values in Pandas DataFrame column替换 Pandas DataFrame 列中超过 n 个连续值
【发布时间】:2017-03-22 08:25:40
【问题描述】:

假设我有以下 DataFrame df

df = pd.DataFrame({"a" : [1,2,2,2,2,2,2,2,2,3,3,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,5,5,5], "b" : [3,3,3,3,3,3,3,4,4,4,4,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,6,6,7,7], "c" : [4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,5,5,5,1,2,2,2,2,2,2,2,2,3,3]})

我希望用 10 个 4 和其余 5 个替换在任何列(可能有数百列)中连续重复超过 10 次的数字 4。

例如,12 个连续的 4 将替换为 10 个 4 和两个 5。

我将如何使用 Pandas 实现这一目标?

我想应用一个 lambda,但我不知道如何回顾足够多的行,它必须从头开始并向前移动,否则会破坏值的顺序。每次查找都必须查看前面的 10 行以查看它们是否都等于 4,如果是,则将当前值设置为 5。

不知道该怎么做!

【问题讨论】:

    标签: python pandas replace multiple-columns cumsum


    【解决方案1】:

    你可以使用:

    #column a is changed for 2 groups of 4
    df = pd.DataFrame({
    "a" : [4,4,4,4,4,4,4,4,4,4,4,4,4,4,7,4,4,4,4,4,4,4,4,4,4,4,4,4,4,5,5,5], 
    "b" : [3,3,3,3,3,3,3,4,4,4,4,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,6,6,7,7], 
    "c" : [4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,5,5,5,1,2,2,2,2,2,2,2,2,3,3]})
    

    如果NaNwhere 创建,则解决方案将连续计数4 并重置,然后将boolean mask 应用于原始df 以将4 替换为5mask

    a = df == 4
    mask = a.cumsum()-a.cumsum().where(~a).ffill().fillna(0) > 10
    df1 = df.mask(mask, 5)
    
    print (df1)
        a  b  c
    0   4  3  4
    1   4  3  4
    2   4  3  4
    3   4  3  4
    4   4  3  4
    5   4  3  4
    6   4  3  4
    7   4  4  4
    8   4  4  4
    9   4  4  4
    10  5  4  5
    11  5  5  5
    12  5  5  5
    13  5  5  5
    14  7  5  5
    15  4  5  5
    16  4  5  5
    17  4  5  5
    18  4  5  5
    19  4  5  5
    20  4  5  5
    21  4  5  1
    22  4  5  2
    23  4  5  2
    24  4  5  2
    25  5  5  2
    26  5  5  2
    27  5  5  2
    28  5  6  2
    29  5  6  2
    30  5  7  3
    31  5  7  3
    

    为了更好地检查值,可以使用concat

    print (pd.concat([df, df1], axis=1, keys=['orig','new']))
       orig       new      
          a  b  c   a  b  c
    0     4  3  4   4  3  4
    1     4  3  4   4  3  4
    2     4  3  4   4  3  4
    3     4  3  4   4  3  4
    4     4  3  4   4  3  4
    5     4  3  4   4  3  4
    6     4  3  4   4  3  4
    7     4  4  4   4  4  4
    8     4  4  4   4  4  4
    9     4  4  4   4  4  4
    10    4  4  4   5  4  5
    11    4  5  4   5  5  5
    12    4  5  4   5  5  5
    13    4  5  4   5  5  5
    14    7  5  4   7  5  5
    15    4  5  4   4  5  5
    16    4  5  4   4  5  5
    17    4  5  4   4  5  5
    18    4  5  5   4  5  5
    19    4  5  5   4  5  5
    20    4  5  5   4  5  5
    21    4  5  1   4  5  1
    22    4  5  2   4  5  2
    23    4  5  2   4  5  2
    24    4  5  2   4  5  2
    25    4  5  2   5  5  2
    26    4  5  2   5  5  2
    27    4  5  2   5  5  2
    28    4  6  2   5  6  2
    29    5  6  2   5  6  2
    30    5  7  3   5  7  3
    31    5  7  3   5  7  3
    

    【讨论】:

    • 谢谢你的回答:)
    • 这太棒了。它如何适用于任何列 - 即如果我想在 a、b 和 c 列上运行它?大概我可以通过for column in df.columns坚持下去?
    • 它适用于所有列,因为所有功能都是为数据框实现的。检查列ac
    • 我添加concat 以便更好地验证输出,请检查上次编辑。
    • 这太不可思议了。你到底是怎么变成这样一只功夫熊猫的?我需要花 30 分钟的时间来了解它是如何工作的,但它工作得很好。谢谢。
    【解决方案2】:

    删除所有 4s,使用 limit=10 作为参数用 4s 填充,并用 5s 删除剩余的 NA。我发现这种方法更明确,更能反映你的意图:

    df[df!=4].fillna(4, limit=10).fillna(5)
    

    如果需要,将 df 转换回最后带有 astype(int) 的整数,因为 NA 的入侵会将数据帧转换为浮点数。

    【讨论】:

    • 只有当列中的一组4 时才有效,请检查我的示例-a 列中的第二组4 将所有值替换为5
    • @jezrael 顺便说一句,有趣的是我被参数文档字符串误导了“如果指定了方法,这是向前/向后填充的连续 NaN 值的最大数量。换句话说,如果有间隙如果连续 NaN 数量超过此数量,则只会部分填充。如果未指定方法,则这是沿整个轴将填充 NaN 的最大条目数。"
    【解决方案3】:

    这应该可以解决问题:

    import pandas as pd
    
    df = pd.DataFrame({"a" : [1,2,2,2,2,2,2,2,2,3,3,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,5,5,5], "b" : [3,3,3,3,3,3,3,4,4,4,4,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,6,6,7,7], "c" : [4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,5,5,5,1,2,2,2,2,2,2,2,2,3,3]})
    
    def replacer(l,target_val=4,replace_val=5,repeat_max=10):
        counter = 0
        new_l = []
        for e in l:
            if e == target_val: counter += 1
            else:
                counter = 0
    
            if counter > repeat_max:
                new_l.append(replace_val)
            else:
                new_l.append(e)
    
        return new_l
    
    df1 = df.apply(replacer)
    

    输出:

        a  b  c
    0   1  3  4
    1   2  3  4
    2   2  3  4
    3   2  3  4
    4   2  3  4
    5   2  3  4
    6   2  3  4
    7   2  4  4
    8   2  4  4
    9   3  4  4
    10  3  4  5
    11  4  5  5
    12  4  5  5
    13  4  5  5
    14  4  5  5
    15  4  5  5
    16  4  5  5
    17  4  5  5
    18  4  5  5
    19  4  5  5
    20  4  5  5
    21  5  5  1
    22  5  5  2
    23  5  5  2
    24  5  5  2
    25  5  5  2
    26  5  5  2
    27  5  5  2
    28  5  6  2
    29  5  6  2
    30  5  7  3
    31  5  7  3
    

    【讨论】:

      猜你喜欢
      • 2014-06-12
      • 1970-01-01
      • 1970-01-01
      • 2019-08-15
      • 1970-01-01
      • 1970-01-01
      • 2021-09-05
      • 1970-01-01
      相关资源
      最近更新 更多