pandas 根据除一行之外的所有行的计算设置像元值

uqjltbpv  于 2023-02-20  发布在  其他
关注(0)|答案(1)|浏览(129)

在一些数据的预处理过程中,我需要删除一些异常值。由于应用程序的性质,我不能删除数据点本身,所以我想用某个范围内其他数据点的最大值来替换它们。例如,假设下面的玩具示例:

import pandas as pd
from scipy import stats

df = pd.DataFrame({
    "Name": ["A", "A", "A", "A", "B", "B", "B", "B"],
    "Value": [1, 2, 30, 4, 10, 200, 30, 40],
    "Class": ["S", "S", "S", "S", "X", "X", "X", "X"]
})

现在,让我们修改远离一个标准差的点(通常,我们在3倍标准差或99.8%百分位数处进行修改,这里仅以一个标准差为例):

df[["zscore"]] = (
    df.groupby(["Name"])
    [["Value"]]
    .transform(lambda x : stats.zscore(x, ddof=1))
)

这就给了我们这样的结果:

Name  Value Class    zscore
0    A      1     S -0.593976
1    A      2     S -0.521979
2    A     30     S  1.493940
3    A      4     S -0.377985
4    B     10     X -0.685248
5    B    200     X  1.484705
6    B     30     X -0.456832
7    B     40     X -0.342624

现在,我想用zscore〉= 1.0替换所有值,以获得下表:

Name  Value Class    zscore
0    A      1     S -0.593976
1    A      2     S -0.521979
2    A      4     S  1.493940
3    A      4     S -0.377985
4    B     10     X -0.685248
5    B     40     X  1.484705
6    B     30     X -0.456832
7    B     40     X -0.342624

请注意,在索引2中,Value从30更改为4。在索引5中,Value从200更改为40。
现在,我的 Dataframe 很大(78M+行),我想使用最高效但仍然很短的代码来完成它。我尝试了以下方法,但它不起作用:

indices = df["zscore"] > 1.0

df.loc[indices] = (
    df[~indices]
    .groupby("Name")
    .max("Value")
)

这给了我

Name  Value Class    zscore
0    A    1.0     S -0.593976
1    A    2.0     S -0.521979
2  NaN    NaN   NaN       NaN
3    A    4.0     S -0.377985
4    B   10.0     X -0.685248
5  NaN    NaN   NaN       NaN
6    B   30.0     X -0.456832
7    B   40.0     X -0.342624

那么,什么是正确的方法呢?保持简短和快速?
当然,我可以做得更详细一点(我不知道这是不是最快的方法):

for name, group in df.groupby("Name"):
    indices = group["zscore"] > 1.0
    df.loc[group[indices].index, ["Value"]] = group[~indices][["Value"]].max()[0]

它产生了我想要的结果

Name  Value Class    zscore
0    A      1     S -0.593976
1    A      2     S -0.521979
2    A      4     S  1.493940
3    A      4     S -0.377985
4    B     10     X -0.685248
5    B     40     X  1.484705
6    B     30     X -0.456832
7    B     40     X -0.342624

谢谢你的帮助。

wgx48brx

wgx48brx1#

假设您有足够的内存来处理数据集,则可以首先掩蔽值列(其中zscore〉1)中的值,然后按名称对掩蔽列进行分组,并使用max进行变换以广播每个组的最大值

m = df['zscore'] > 1
df.loc[m, 'Value'] = df['Value'].mask(m).groupby(df['Name']).transform('max')
Name  Value Class    zscore
0    A      1     S -0.593976
1    A      2     S -0.521979
2    A      4     S  1.493940
3    A      4     S -0.377985
4    B     10     X -0.685248
5    B     40     X  1.484705
6    B     30     X -0.456832
7    B     40     X -0.342624

相关问题