【问题标题】:Randomly introduce NaN values in pandas dataframe在 pandas 数据框中随机引入 NaN 值
【发布时间】:2019-06-17 05:35:23
【问题描述】:

考虑到我的起始数据中已经存在的空值,我如何将 NaN 值随机引入我的数据集中的每一列。

我想按列拥有例如 20% 的 NaN 值。

例如:
如果我的数据集中有 3 列:每列的“A”、“B”和“C”我有 NaN 值率我如何按列随机引入 NaN 值以达到每列 20%:

A: 10% nan
B: 15% nan
C: 8% nan

目前我尝试了这段代码,但它降低了我的数据集太多,我认为这不是好方法:

df = df.mask(np.random.choice([True, False], size=df.shape, p=[.20,.80]))

【问题讨论】:

  • 但是您提供的代码有效吗?因为如果您已经有现有的 NaN 值,您可能会超过每列中所需的 20%。
  • 是的,我有现有的 NaN 值,我希望每列中的 20% 不超过或不超过。
  • 是的,它工作的代码,但我认为它在数据集中引入了 20%,而不是每列。

标签: python pandas numpy dataframe nan


【解决方案1】:

我不确定最后一部分是什么意思(“降级太多”),但这是一种粗略的方法。

import numpy as np
import pandas as pd

A = pd.Series(np.arange(99))

# Original missing rate (for illustration)
nanidx = A.sample(frac=0.1).index
A[nanidx] = np.NaN

###
# Complementing to 20%
# Original ratio
ori_rat = A.isna().mean()

# Adjusting for the dataframe without missing values
add_miss_rat = (0.2 - ori_rat) / (1 - ori_rat)

nanidx2 = A.dropna().sample(frac=add_miss_rat).index
A[nanidx2] = np.NaN

A.isna().mean()

显然,它并不总是正好是 20%...

更新 将其应用于整个数据框

for col in df:
    ori_rat = df[col].isna().mean()

    if ori_rat >= 0.2: continue

    add_miss_rat = (0.2 - ori_rat) / (1 - ori_rat)
    vals_to_nan = df[col].dropna().sample(frac=add_miss_rat).index
    df.loc[vals_to_nan, col] = np.NaN

更新 2 我进行了更正,以在计算比率时还考虑到删除 NaN 值的影响。

【讨论】:

  • 我的例子只是为了说明,但基本上我不知道我的 df 和每一列的 NaN 率。理想情况下,需要计算每列 NaN 值的比率,然后随机按 NaN 值完成,最终按列有 20% 的 NaN 值。
  • 您可以忽略第一部分(我生成原始 nan rate 的地方)。那只是为了说明。第二部分为特定列执行您需要的操作(当然,它还在途中计算原始缺失值......)。
  • 当我执行代码时,我有这个 ValueError:请求的行数为负数。请提供正值。
  • 这是因为一些原始缺失率高于0.2。我调整了代码,使其保持不变。
【解决方案2】:

除非你有一个巨大的 DataFrame 并且速度是一个问题,否则最简单的方法就是迭代。

import pandas as pd
import numpy as np
import random

df = pd.DataFrame({'A':list(range(100)),'B':list(range(100)),'C':list(range(100))})
#before adding nan
print(df.head(10))

nan_percent = {'A':0.10, 'B':0.15, 'C':0.08}

for col in df:
    for i, row_value in df[col].iteritems():
        if random.random() <= nan_percent[col]:
            df[col][i] = np.nan
#after adding nan            
print(df.head(10))

【讨论】:

  • 如果我有一个大数据集(> 100 列)我应该如何在 nan_percent 中做?
  • 同理,它是基于random.random()的输出,它是一个从0到1的随机浮点数。10% = 0.1, 1%=0.01等。列的长度不'没关系。
  • 如果我有 40 列需要多长时间?我在我的代码中执行了它,但它已经超过 30 分钟了
  • 这取决于列数和行数。很难说,因为它也取决于您的硬件。 30分钟听起来太多了。你的df是多少行?
  • 我认为我的硬件很好。我有 150 000 行和 40 列。在此之前,我为自己构建了一个字典,并将列的集合与我想要降级的值放在一起
【解决方案3】:

这是一种使每列中的 nan 尽可能接近 20% 的方法:

def input_nan(x,pct):
    n = int(len(x)*(pct - x.isna().mean()))
    idxs = np.random.choice(len(x), max(n,0), replace=False, p=x.notna()/x.notna().sum())
    x.iloc[idxs] = np.nan

df.apply(input_nan, pct=.2)

它首先获取您想要的NaN 百分比与数据集中已有的NaN 值之间的差异。然后它将它乘以列的长度,得到你想要放入多少个NaN 值(n)。然后使用np.random.choice 随机选择其中没有NaN 值的n 索引。

例子:

df = pd.DataFrame({'y':np.random.randn(10), 'x1':np.random.randn(10), 'x2':np.random.randn(10)})
df.y.iloc[1]=np.nan
df.y.iloc[8]=np.nan
df.x2.iloc[5]=np.nan

#           y        x1        x2
# 0  2.635094  0.800756 -1.107315
# 1       NaN  0.055017  0.018097
# 2  0.673101 -1.053402  1.525036
# 3  0.246505  0.005297  0.289559
# 4  0.883769  1.172079  0.551917
# 5 -1.964255  0.180651       NaN
# 6 -0.247067  0.431622 -0.846953
# 7  0.603750  0.475805  0.524619
# 8       NaN -0.452400 -0.191480
# 9 -0.583601 -0.446071  0.029515

df.apply(input_nan)

#           y        x1        x2
# 0  2.635094  0.800756 -1.107315
# 1       NaN  0.055017  0.018097
# 2  0.673101 -1.053402  1.525036
# 3  0.246505  0.005297       NaN
# 4  0.883769  1.172079  0.551917
# 5 -1.964255       NaN       NaN
# 6 -0.247067  0.431622 -0.846953
# 7  0.603750       NaN  0.524619
# 8       NaN -0.452400 -0.191480
# 9 -0.583601 -0.446071  0.029515

我已将其应用于整个数据集,但您可以将其应用于您想要的任何列。例如,如果您希望列 yx1 中的 NaN 为 15%,您可以调用 df[['y','x1]].apply(input_nan, pct=.15)

【讨论】:

  • 我明白了,但是我有一个超过 100 列的大型数据集,我可以为每一列执行此操作。
  • 这并没有改变我的 df,因为我计算了每列前后的 NaN 率并且没有变化
  • 嗯,在我的示例中它适用于 df。你调用了什么,你调用它的列之前和之后的 NaN 百分比是多少?
  • 刚刚将该函数应用于包含 10,000 个观察值的数据框(在应用该函数之前混合了 NaN 百分比)。调用 df.isna().mean() 会得到想要的结果:y = 0.2, x1 = 0.2, x2 = 0.2
【解决方案4】:

我想我参加聚会有点晚了,但如果有人需要一个更快的解决方案,并在引入空值时考虑百分比值,代码如下:

nan_percent = {'A':0.15, 'B':0.05, 'C':0.23}

for col, perc in nan_percent.items():
    df['null'] = np.random.choice([0, 1], size=df.shape[0], p=[1-perc, perc])
    df.loc[df['null'] == 1, col] = np.nan

df.drop(columns=['null'], inplace=True)

【讨论】:

    猜你喜欢
    • 2016-12-27
    • 2016-02-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-12-03
    • 1970-01-01
    • 2020-04-11
    • 2021-08-01
    相关资源
    最近更新 更多