我有数据框
ID Value
A 70
A 80
A 1000
A 100
A 200
A 130
A 60
A 300
A 800
A 200
A 150
A 250
我需要将异常值替换为中值。 我用
df = pd.read_excel("test.xlsx")
grouped = df.groupby('ID')
statBefore = pd.DataFrame({'q1': grouped['Value'].quantile(.25), \
'median': grouped['Value'].median(), 'q3' :
grouped['Value'].quantile(.75)})
def is_outlier(row):
iq_range = statBefore.loc[row.ID]['q3'] - statBefore.loc[row.ID]['q1']
median = statBefore.loc[row.ID]['median']
q3 = statBefore.loc[row.ID]['q3']
q1 = statBefore.loc[row.ID]['q1']
if row.Value > (q3 + (3 * iq_range)) or row.Value < (q1 - (3 * iq_range)):
return True
else:
return False
#apply the function to the original df:
df.loc[:, 'outlier'] = df.apply(is_outlier, axis = 1)
但是它会返回中位数 - 175
和q1 - 92
,但我得到 - 90
,它会返回q3 - 262,5
,但我算得上 - 275
。
那有什么不对?
答案 0 :(得分:0)
这很简单,性能很好,没有Python for循环来降低速度:
s = pd.Series([30, 31, 32, 45, 50, 999]) # example data
s.where(s.between(*s.quantile([0.25, 0.75])), s.median())
它给你:
0 38.5
1 38.5
2 32.0
3 45.0
4 38.5
5 38.5
解压缩该代码,我们s.quantile([0.25, 0.75])
来获取此代码:
0.25 31.25
0.75 48.75
然后我们使用值(31.25和48.75)作为between()
的参数,并使用*
运算符解压缩它们,因为between()
需要两个单独的参数,而不是长度为2的数组那给了我们:
0 False
1 False
2 True
3 True
4 False
5 False
现在我们有二进制掩码,我们使用s.where()
选择True
位置的原始值,否则返回s.median()
。
答案 1 :(得分:0)
这就是分位数的定义方式
df = pd.DataFrame(np.array([60,70,80,100,130,150,200,200,250,300,800,1000]))
print df.quantile(.25)
print df.quantile(.50)
print df.quantile(.75)
(数据集的q1为95 btw)
中位数介于150和200之间(175)
第一个分位数是80到100(95)之间的3个季度
第三个分位数是250到300(262.5)
之间的四分之一