代码之家  ›  专栏  ›  技术社区  ›  MarkS

在特定值范围内填充列中的NaN值

  •  0
  • MarkS  · 技术社区  · 6 年前

    使用特定范围内的值在单个列中填充NaN值。

    我想使用的范围是列中非Nan值的平均值+/-1一个标准 计算平均值的偏差。

    注意 一个常数。

    我以为我有它(见下面的完整代码),但是 print(df['C'].describe()) 表明

    import pandas as pd
    import numpy as np
    import sys
    
    print('Python: {}'.format(sys.version))
    print('NumPy: {}'.format(np.__version__))
    print('Pandas: {}'.format(pd.__version__))
    print('\033[1;31m' + '--------------' + '\033[0m')  # Bold red
    
    display_settings = {
        'max_columns': 15,
        'max_colwidth': 60,
        'expand_frame_repr': False,  # Wrap to multiple pages
        'max_rows': 50,
        'precision': 6,
        'show_dimensions': False
    }
    # pd.options.display.float_format = '{:,.2f}'.format
    
    for op, value in display_settings.items():
        pd.set_option("display.{}".format(op), value)
    
    df = pd.DataFrame(np.random.randint(0, 1000, size=(200, 10)), columns=list('ABCDEFGHIJ'))
    # df = pd.DataFrame(np.random.randint(0, 100, size=(20, 4)), columns=list(['AA','BB','C2','D2']))
    print(df, '\n')
    
    # https://stackoverflow.com/questions/55149738/pandas-replace-values-with-nan-at-random
    df['C'] = df['C'].sample(frac=0.65)  # The percentage of non-NaN values.
    df['H'] = df['H'].sample(frac=0.75)  # The percentage of non-NaN values.
    print(df, '\n')
    print(df.isnull().sum(), '\n')
    print(df['C'].describe(), '\n')
    
    def fillNaN_with_unifrand(col):
        a = col.values
        m = np.isnan(a)  # mask of NaNs
        mu, sigma = col.mean(), col.std()
        a[m] = np.random.normal(mu, sigma, size=m.sum())
        return col
    
    
    # https://stackoverflow.com/questions/46543060/how-to-replace-every-nan-in-a-column-with-different-random-values-using-pandas?rq=1
    fillNaN_with_unifrand(df['C'])
    pd.options.display.float_format = '{:.0f}'.format
    print(df, '\n')
    print(df.isnull().sum(), '\n')
    print(df['C'].describe())
    

    输出 :

    count    130.000000
    mean     462.446154
    std      290.760432
    min        7.000000
    25%      187.500000
    50%      433.000000
    75%      671.250000
    max      992.000000
    Name: C, dtype: float64 
    

    count    200
    mean     517
    std      298
    min     -187
    25%      281
    50%      544
    75%      763
    max     1218
    Name: C, dtype: float64
    

    注意最小值和最大值。我的所有填充值(在本例中)应该是462+/-290。

    0 回复  |  直到 6 年前
        1
  •  1
  •   offeltoffel    6 年前

    好吧,这不是统计工作的方式。高斯正态分布有一个均值和一个std,但是值可以远离mean+-std,它们只是不太可能。根据正态分布的定义,68%的值在+1*std范围内,95%在+2*std范围内,依此类推。问题是:你想如何处理异常值?把它们设为+性病还是再画一次?

    这通常是不需要的,因为这会改变分布,并在上下边界上施加更多的权重。

    from matplotlib import pyplot as plt
    
    mu = 100
    sigma = 7
    a = np.random.normal(mu, sigma, size=2000) # I used a size of 2000 as an example
    a[a<(mu-sigma)] = mu-sigma
    a[a>(mu+sigma)] = mu+sigma
    plt.hist(a, bins=12, edgecolor='black')
    plt.show()
    

    Outliers set to min/max of the wanted range

    情形2:截尾正态分布

    你通常想要的是 Truncated Normal Distribution . 它创建具有上下边界的分布。你可以在 scipy.stats rvs 像这样:

    from matplotlib import pyplot as plt
    import scipy.stats as stats
    
    mu = 100
    sigma = 7
    lower_clip = mu-sigma
    upper_clip = mu+sigma
    a = stats.truncnorm((lower_clip - mu) / sigma, (upper_clip - mu) / sigma, loc=mu, scale=sigma)
    plt.hist(a.rvs(2000), bins=12, edgecolor='black')
    plt.show()
    

    Truncated Normal Distribution

    sigma的倍数常数易于实现。你可以改变你的上下夹

    lower_clip = mu-x*sigma