Python:numpy/pandas 根据条件更改值
我想知道有没有更快、更“pythonic”的方法来做以下事情,比如使用一些内置的方法。给定一个包含浮点数的pandas DataFrame或numpy数组,如果某个值小于或等于0.5,我需要计算这个值的倒数,然后乘以-1,并用新计算的值替换旧值。这里用“转换”这个词可能不太合适,如果你有更好或更准确的描述,请告诉我。
谢谢你的帮助和支持!!
数据:
import numpy as np
import pandas as pd
dicti = {"A" : np.arange(0.0, 3, 0.1),
"B" : np.arange(0, 30, 1),
"C" : list("ELVISLIVES")*3}
df = pd.DataFrame(dicti)
我的函数:
def transform_colname(df, colname):
series = df[colname]
newval_list = []
for val in series:
if val <= 0.5:
newval = (1/val)*-1
newval_list.append(newval)
else:
newval_list.append(val)
df[colname] = newval_list
return df
函数调用:
transform_colname(df, colname="A")
**--> 我在这里总结结果,因为评论不允许发布代码(或者我不知道怎么做)。**
非常感谢大家快速而出色的回答!!
使用ipython的“%timeit”命令和“真实”数据:
我的函数: 10次循环,最佳结果为3次:每次循环24.1毫秒
来自jojo的回答:
def transform_colname_v2(df, colname):
series = df[colname]
df[colname] = np.where(series <= 0.5, 1/series*-1, series)
return df
100次循环,最佳结果为3次:每次循环2.76毫秒
来自FooBar的回答:
def transform_colname_v3(df, colname):
df.loc[df[colname] <= 0.5, colname] = - 1 / df[colname][df[colname] <= 0.5]
return df
100次循环,最佳结果为3次:每次循环3.32毫秒
来自dmvianna的回答:
def transform_colname_v4(df, colname):
df[colname] = df[colname].where(df[colname] <= 0.5, (1/df[colname])*-1)
return df
100次循环,最佳结果为3次:每次循环3.7毫秒
如果你有不同的实现方式,请告诉我或展示给我看!
最后一个问题:(已回答)
如何让“FooBar”和“dmvianna”的版本变得“通用”?我的意思是,我必须在函数中写列的名称(因为把它作为变量使用不行)。请解释一下这一点!
--> 谢谢jojo,“.loc”不是正确的方法,但简单的df[colname]就足够了。把上面的函数改得更“通用”了。(还把“>”改成了“<=”,并更新了时间)
非常感谢!!
3 个回答
就像@jojo的回答那样,不过这里用的是pandas库:
df.A = df.A.where(df.A > 0.5, (1/df.A)*-1)
或者
df.A.where(df.A > 0.5, (1/df.A)*-1, inplace=True) # this should be faster
这是.where的说明:
定义: df.A.where(self, cond, other=nan, inplace=False, axis=None, level=None, try_cast=False, raise_on_error=True)
说明: 这个方法会返回一个和原对象形状相同的对象,满足条件的地方会取自原对象,而不满足条件的地方则会取自其他指定的值。
通常的做法是写一个通用的数学运算,用来处理整列数据,但实际上我们会用一些标记来选择哪些行需要应用这个运算:
df.loc[df.A < 0.5, 'A'] = - 1 / df.A[df.A < 0.5]
In[13]: df
Out[13]:
A B C
0 -inf 0 E
1 -10.000000 1 L
2 -5.000000 2 V
3 -3.333333 3 I
4 -2.500000 4 S
5 0.500000 5 L
6 0.600000 6 I
7 0.700000 7 V
8 0.800000 8 E
9 0.900000 9 S
10 1.000000 10 E
11 1.100000 11 L
12 1.200000 12 V
13 1.300000 13 I
14 1.400000 14 S
15 1.500000 15 L
16 1.600000 16 I
17 1.700000 17 V
18 1.800000 18 E
19 1.900000 19 S
20 2.000000 20 E
21 2.100000 21 L
22 2.200000 22 V
23 2.300000 23 I
24 2.400000 24 S
25 2.500000 25 L
26 2.600000 26 I
27 2.700000 27 V
28 2.800000 28 E
29 2.900000 29 S
如果我们在讨论数组的话题:
import numpy as np
a = np.array([0.1, 0.2, 0.3, 0.4, 0.5, 0.6], dtype=np.float)
print 1 / a[a <= 0.5] * (-1)
不过,这样做只会返回小于0.5
的值。
另外,你可以使用np.where
:
import numpy as np
a = np.array([0.1, 0.2, 0.3, 0.4, 0.5, 0.6], dtype=np.float)
print np.where(a < 0.5, 1 / a * (-1), a)
接下来谈谈pandas
的数据框:
就像@dmvianna的回答那样(所以要给他一些赞扬哦;)),我们可以把它调整为pd.DataFrame
:
df.a = df.a.where(df.a > 0.5, (1 / df.a) * (-1))