我要执行以下操作:
使用特定范围内的值在单个列中填充NaN值。
我要使用的范围是+/- 1列标准中非Nan值的平均值 计算平均值的偏差。
注意如果可能的话,我希望能够通过将std dev乘以来使用std dev的倍数 一个常数。
我以为我有它(请参见下面的完整代码),但是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())
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 :(得分:1)
嗯,这不是统计信息的工作方式。高斯正态分布具有一个平均值和一个std,但是可以将值绘制得远离平均值+ -std,它们的似然度更低。根据正态分布的定义,所有值的68%在+ -1 * std范围内,95%在+ -2 * std范围内,依此类推。问题是:您想对异常值做什么?将它们设置为+ -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()
您通常想要的是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()
很容易实现sigma倍数的常数。您可以像这样更改上下剪辑
lower_clip = mu-x*sigma
以x为常数。