Pandas:根据其他列中的值更改删除数据框的百分比

Pandas: Delete percentage of dataframe dependent on value change in other column

我有一个非常大的数据框(大约 50 亿行和 13 列)。其中一列的值可以为 0 和 1,分别表示非活动和活动模式。通常有几行非活动模式 (0),后面是几行活动模式 (1)。因此,首先是一个非活动段,然后是一个活动段,然后是一个非活动段,依此类推。

像这样:

df = pd.DataFrame(np.random.randint(0,100,size=(30, 4)), columns=list('ABCD'))
df['E'] = [0,0,0,0,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,1,1,1,1,1,1,0,0,0]

    A   B   C   D  E
0   53  27  10  49  0
1   39  46  89  33  0
2   32  43   7  15  0
3   16  36  33  18  0
4   12   3  94  96  1
5   31  22  64  51  1
6   79  93  93  67  1
7   85  27  10  19  1
8    4  92  38  38  1
9   79   8   6  90  1
10  68   6  26  24  1
11  89  49  23  91  1
12  44  17  40  75  1
13  12  18  17  87  1
14  76  67  74  15  0
15   9  37   8  92  0
16  52  53  93  47  0
17  74   3  27  96  0
18  77  10  93   8  0
19  64  33  46  79  0
20  72   9  36  99  0
21  75  13  76  49  1
22  95  21  88  77  1
23  46  45  36  20  1
24  61  26  72  48  1
25  35  62  98  28  1
26  91  43  23  42  0
27  25  59   6  30  0
28  20  31   2  76  0
29   2  25  86  12  0

我需要删除每个活动段的前 20%,非活动段应保持原样。所以它应该是这样的:

    A   B   C   D  E
0   53  27  10  49  0
1   39  46  89  33  0
2   32  43   7  15  0
3   16  36  33  18  0
6   79  93  93  67  1
7   85  27  10  19  1
8    4  92  38  38  1
9   79   8   6  90  1
10  68   6  26  24  1
11  89  49  23  91  1
12  44  17  40  75  1
13  12  18  17  87  1
14  76  67  74  15  0
15   9  37   8  92  0
16  52  53  93  47  0
17  74   3  27  96  0
18  77  10  93   8  0
19  64  33  46  79  0
20  72   9  36  99  0
22  95  21  88  77  1
23  46  45  36  20  1
24  61  26  72  48  1
25  35  62  98  28  1
26  91  43  23  42  0
27  25  59   6  30  0
28  20  31   2  76  0
29   2  25  86  12  0

我已经使用 df.diff() 添加了一个额外的列,显示从非活动到活动的变化发生的位置,反之亦然:

     A   B   C   D  E  E_diff
0   53  27  10  49  0     NaN
1   39  46  89  33  0     0.0
2   32  43   7  15  0     0.0
3   16  36  33  18  0     0.0
4   12   3  94  96  1     1.0
5   31  22  64  51  1     0.0
6   79  93  93  67  1     0.0
7   85  27  10  19  1     0.0
8    4  92  38  38  1     0.0
9   79   8   6  90  1     0.0
10  68   6  26  24  1     0.0
11  89  49  23  91  1     0.0
12  44  17  40  75  1     0.0
13  12  18  17  87  1     0.0
14  76  67  74  15  0    -1.0
15   9  37   8  92  0     0.0
16  52  53  93  47  0     0.0
17  74   3  27  96  0     0.0
18  77  10  93   8  0     0.0
19  64  33  46  79  0     0.0
20  72   9  36  99  0     0.0
21  75  13  76  49  1     1.0
22  95  21  88  77  1     0.0
23  46  45  36  20  1     0.0
24  61  26  72  48  1     0.0
25  35  62  98  28  1     0.0
26  91  43  23  42  0    -1.0
27  25  59   6  30  0     0.0
28  20  31   2  76  0     0.0
29   2  25  86  12  0     0.0

我不知道如何确定段的长度,然后删除正确的行。我需要为此编写一个循环还是有更简单的方法?我如何确定要删除的行的正确索引值?

这样就可以了。这是两个独立的 Whosebug 答案的拼凑而成: and :

df['flag'] = df.E.diff().ne(0).cumsum()

def mask_first(x,ratio=0.2):
    result = np.ones_like(x,dtype=bool)
    result[0:math.ceil(len(x)*ratio)] = False 
    return result

mask = df.groupby(['flag'])['flag'].transform(mask_first).astype(bool)
df[(df.E == 0) | mask].drop('flag',axis=1)

输出为:

idx A   B   C   D   E
0   77  44  52  17  0
1   75  61  69  6   0
2   79  87  99  31  0
3   42  10  3   98  0
6   53  68  86  92  1
7   25  3   27  84  1
8   18  60  93  79  1
...