首页 > 解决方案 > 如何根据给定条件 pandas/python 删除 *some* 行

问题描述

我正在使用 Pandas 中的数据集,我想根据给定条件删除一些行。我的数据集中有一列是参与者的合并症数量,可能的值为 0、1、2、3。数据集大约有 100 万行(和 30 个其他列),大约 50 万参与者 = 0 合并症,约 300,000 名参与者 = 1 种合并症,约 130,000 名参与者 = 2 种合并症,约 75,000 名参与者 = 3 种合并症。我想根据他们的合并症值随机删除参与者组,例如,删除 200k 与 0 合并症,100k 与 1 合并症。我知道如果想放弃所有合并症数量给定的参与者,例如所有合并症为 0 的参与者,我可以执行以下操作:

数据框 = allpart,列名 = CM

allpart.drop(allpart[allpart['CM'] == 0].index, inplace = True) 

我怎么能改变它,让它随机选择 300k 行 w/0 合并症?我的数据框没有按该列按升序排列,因此排除了删除一大块行的可能性,我也不确定这是否足够随机。我还想提一下,我不会以此为依据得出任何合理的结论,这只是为了我自己的利益。

谢谢!

标签: pythonpandasdataframe

解决方案


一种解决方案是定义您希望为每种合并症保留多少行,然后groupby+sample选择该大小的随机子集。

我添加了一个小检查,以防您指定的行数大于该'CM'组的 DataFrame 中存在的唯一行数。在这种情况下,它只返回所有行。

import pandas as pd
import numpy as np
np.random.seed(410112)

df = pd.DataFrame({'id': range(20), 'CM': np.random.choice([0,1,2,3,4], 20)})
# Keys is comorbidity index, value is # of rows to keep 
d = {0: 1, 1: 3, 2: 2, 3: 20, 4: 2}

l = []
for idx, gp in df.groupby('CM'):
    try:
        gp = gp.sample(n=d[idx], replace=False)
    # If try to subsample more people than exist, do nothing
    except ValueError:
        pass 
    l.append(gp)
    
df1 = pd.concat(l)

    id  CM
3    3   0
17  17   1
13  13   1
5    5   1
19  19   2
7    7   2
1    1   3
4    4   3
10  10   3
12  12   4
0    0   4

另一种类似但不需要重建整个 DataFrame(可能更快)的替代方法是再次指定d要保留的行数的字典并用于sample(frac=1)对 DataFrame 进行洗牌,然后groupby+cumcount保留行的随机子集。

# Keys is comorbidity index, value is # of rows to keep 
d = {0: 1, 1: 3, 2: 2, 3: 20, 4: 2}

mask = df.sample(frac=1).groupby('CM', sort=False).cumcount().lt(df['CM'].map(d))
df1 = df[mask]

# Different subset of rows but still 1 row with CM0, 3 with CM1, ...

    id  CM
9    9   0
5    5   1
15  15   1
17  17   1
6    6   2
7    7   2
1    1   3
4    4   3
10  10   3
0    0   4
12  12   4

推荐阅读