优化代码,将大于中位数的值替换为中位数值,适用于pandas DataFrame
我想把某一列中所有高于中位数的值替换成这个列的中位数。
这是我的数据框:
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的where 和 apply 方法,来对数据表中的所有列进行操作:
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