用从上到下的某个值将连续出现的数字替换为相等的数量

时间:2019-11-12 10:04:15

标签: python pandas dataframe

我有一个这样的数据框,

df
col1    col2
  1      A
  2      B
  3      B
  4      B
  5      B
  6      C
  7      A
  8      A
  9      A
  10     A
  11     B
  12     C

现在,如果要在col2中连续出现任意值是4(让我们说n1)替换两个(让我们说n2)值(一个从上到下,一个从下到下)的情况下,我想从上面的数据帧创建一个数据帧)的任何值都可以说('D')

我想创建一个函数,让它说f(df,n1,n2,'D'),这将返回以下数据帧,

col1    col2
  1      A
  2      D
  3      B
  4      B
  5      D
  6      C
  7      D
  8      A
  9      A
  10     D
  11     B
  12     C

我可以使用for循环来执行此操作,但是执行时间将非常长,我正在寻找pandas快捷方式/ pythonic方式来实现。

2 个答案:

答案 0 :(得分:2)

如果col2列中没有缺失值,则解决方案有效:

def f(df, n1, n2, val):

    #count consecutive values of col2
    s = df.groupby(df['col2'].ne(df['col2'].shift()).cumsum())['col2'].transform('size')

    #compare by threshold and create missing values, with forward and back replacement
    m1 = s >= n1
    m2 = df['col2'].mask(m1).ffill(limit=n2).bfill(limit=n2).notna()

    #chain masks and set val
    df['col2'] = df['col2'].mask(m1 & m2, val)
    return df

df1 = f(df,4,1,'D')

print (df1)
    col1 col2
0      1    A
1      2    D
2      3    B
3      4    B
4      5    D
5      6    C
6      7    D
7      8    A
8      9    A
9     10    D
10    11    B
11    12    C

如果可能的话,一些缺失的值是必要的,用一些值替换它们:

def f(df, n1, n2, val):

    a = df['col2'].fillna('tmp')

    s = a.groupby(a.ne(a.shift()).cumsum()).transform('size')

    m1 = s >= n1
    m2 = a.mask(m1).ffill(limit=n2).bfill(limit=n2).notna()

    df['col2'] = df['col2'].mask(m1 & m2, val)
    return df

答案 1 :(得分:0)

df.groupby((df['col2'] != df['col2'].shift()).cumsum())['col2'] \ 
  .transform(lambda x: x if len(x) < 4 else ['D']+x.iloc[1:-1].tolist()+['D'])

0     A
1     D
2     B
3     B
4     D
5     C
6     D
7     A
8     A
9     D
10    B
11    C