优化代码,将大于中位数的值替换为中位数值,适用于pandas DataFrame

1 投票
2 回答
648 浏览
提问于 2025-04-18 18:41

我想把某一列中所有高于中位数的值替换成这个列的中位数。

这是我的数据框:

m = pd.DataFrame({
    'a': xrange(5),
    'b': xrange(5, 10),
    'c': xrange(10,15)})

print m

    a   b   c
0   0   5   10
1   1   6   11
2   2   7   12
3   3   8   13
4   4   9   14

这是我的解决方案:

for col in m.columns:
    quart = m[col].median()
    m[col] = [val if val < quart else quart for val in m[col]]

print m

    a   b   c
0   0   5   10
1   1   6   11
2   2   7   12
3   2   7   12
4   2   7   12

我对数据框不太熟悉,所以我在想有没有更“pandas”的方法,或者用一些高级的线性代数来实现。

提前谢谢你的回复。


编辑回答:

这是对hurrial和chrisb的解决方案进行快速计时的结果:

%timeit m.apply(lambda col: np.where(col.median() < col, col.median(), col))
1000 loops, best of 3: 1.36 ms per loop

%timeit np.minimum(m, m.median())
1000 loops, best of 3: 400 µs per loop

使用np.minimum的解决方案似乎更快。

谢谢你,今天我学到了两个很强大的东西,np.where和np.minimum!

2 个回答

0

你可以使用 numpy的whereapply 方法,来对数据表中的所有列进行操作:

    import numpy as np
    import pandas as pd

    m = pd.DataFrame({
        'a': range(5),
        'b': range(5, 10),
        'c': range(10,15)})

    print(m)
        a   b   c
    0   0   5   10
    1   1   6   11
    2   2   7   12
    3   3   8   13
    4   4   9   14

    m.apply(lambda col: np.where(col.median()>col, col.median(), col))

    print(m)

        a   b   c
    0   2   7   12
    1   2   7   12
    2   2   7   12
    3   3   8   13
    4   4   9   14
0

有几种不同的方法可以做到这一点。一般来说,使用列表推导式来表达pandas操作并不是一个高效的方法——那一行代码可以重写成其他形式(可以参考索引文档)。

m.loc[m[col] >= val, col] = quart

不过,整个操作可以用一行代码来完成,像这样(需要导入numpy as np):

In [211]: m = np.minimum(m, m.median())

In [212]: m
Out[212]: 
   a  b   c
0  0  5  10
1  1  6  11
2  2  7  12
3  2  7  12
4  2  7  12

撰写回答