仅针对大多数 class 个样本删除缺失数据百分比超过百分比的行

Remove rows with more than percentage of missing data for majority class samples only

与此类似post,我正在删除缺失数据超过 50% 的行以获得更可靠和完整的数据集

# Keep only the rows with at least x% non-NA values

# calculate threshold
numOfFeatures=38 # num of features in dataset
x=round(numOfFeatures*0.5) #50%

dfWithDroppedRows = df.dropna(thresh=x)

但是,我有一个不平衡的数据集,其中大多数 class 几乎占我数据集的 93%

df['y'].value_counts(normalize=True) * 100
No     92.769441
Yes     7.230559

因此,我想编辑上面的代码,仅从大多数 class 的样本中删除缺失数据超过 50% 的行,这样我就不会丢失少数 class 的样本。

为此,我尝试过:

dfWithDroppedRows = df[df['y'] == 'No'].dropna(thresh=x)

但这会导致 dfWithDroppedRows 仅包含来自多数 class 的减少行,而不包含来自少数 class 的样本。我想我可以通过将 dfWithDroppedRows 与 df[df['y'] == 'Yes'] 连接来解决这个问题,但我觉得应该有一种更直接的方法来做到这一点。有什么建议吗?

在我看来,连接两个 DataFrame 并不是一个坏主意,但如果您不喜欢,这是我的建议。

mask_majority = df.eval("y == 'No'")
mask_missing = df.isna().sum(axis="columns") >= x

import numpy as np

mask_drop = np.logical_and(mask_majority, mask_missing)
mask_keep = np.logical_not(mask_drop)
dfWithDroppedRows = df.loc[mask_keep, :]

基本上,我为大多数 class 创建了一个掩码,并为缺失值超过 x 的所有行创建了一个掩码。 然后我将这两个掩码组合起来得到一个包含所有不能删除的行的掩码,我得到的 DataFrame 只包含那些使用 .loc.

的行

顺便说一句,如果您决定使用连接两个 DataFrame 的初始解决方案,我会改用 query 方法,它更惯用:

df_majority_droppedRows = df.query("y == 'No'").dropna(thresh=x)
df_minority = df.query("y == 'Yes'")
dfWithDroppedRows = pd.concat([df_majority_droppedRows, df_minority])