我有一个看起来像这样的数据框架:
idx a b c d e f g h i j
1 0 17 17 83 17 0 21 16 21 4
2 -9 31 31 74 40 0 39 39 39 9
3 -27 0 -27 92 27 -37 3 -37 40 16
4 -4 0 -4 81 4 -1 5 5 6 9
我想申请:
where x>0: functionA(x)
where x<0: functionB(x)
我独立尝试的是:
df[df>0] = np.log(df)
和
df[df<0] = -np.log(-df)
哪种有效的作用。.顺序运行这两个操作将无法使用,因为数据框在第一个操作后从int转换为float,并且从log values,ex ex。毫无差异的原始值。是0还是log(1)= 0?
我也担心这些错误:
除以零
usr/local/anaconda3/envs/ds/lib/python3.6/site-packages/ipykernel_launcher.py:1: RuntimeWarning: divide by zero encountered in log
"""Entry point for launching an IPython kernel.```
无效的值
/usr/local/anaconda3/envs/ds/lib/python3.6/site-packages/ipykernel_launcher.py:1: RuntimeWarning: invalid value encountered in log
"""Entry point for launching an IPython kernel.
由于没有NaN
值,因此我明确选择了非零值。
df.isnull().values.any()
False
最后一个问题是如何在与数十亿行合作时如何有效地执行此操作。
您可以使用 numpy.piecewise
函数:https://docs.scipy.org/doc/numpy-1.13.0/reference/generated/numpy.piecewise.piecewise.html
import numpy as np
positive = df.values > 0
negative = df.values < 0
df[:] = np.piecewise(df.values, (positive, negative), (np.log, lambda x: -np.log(-x)))
可能有更好的方法,但现在是我所做的:
将我的专栏分为三种:
- (-Inf,0)
- (0,inf)
- (-INF,INF)
前两个很简单[1]:
for i in [a, ...]:
s = df[i]
df[i] = np.where(s<0, -np.log(-s), s).astype('float32')
类型2的类似代码。
类型3更棘手,较慢:
def apply_log(x):
if x>0:
return np.log(x)
elif x<0:
return -np.log(-x)
elif x == 0:
return 0.0
else:
assert False
然后将其矢量化[2]
veclog = np.vectorize(apply_log)
然后运行它: df['c'] = veclog(s.astype('float32')).astype('float32')
〜50m子集的运行时: 57.7 s ± 142 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
从[3]带有np.where
,在条件之前应用FN,因此除以零误差。类型1和2将鸿沟丢为零警告/错误,第3型中没有错误。
来源:
[1] python:numpy/pandas在条件上更改值
[2]函数应用程序通过Numpy的矩阵行/列
[3] Runtime Warning:在日志中遇到的零零分隔
有人在之前添加了此答案,然后删除它:
df = np.log(df.where(df>0)).fillna(-1*np.log(-1*df.where(df<0))).fillna(0)
使用了大量内存,但似乎有效。我有一个怀疑,因为它按顺序运行OP,并且可能会使某些值运行。
update :这似乎与.0005中其他解决方案的答案匹配。如果原始海报会重新发布他们的答案!