加速大熊猫数据框中的iloc解决方案

Ant*_*y W 8 python dataframe pandas

我有以下内容DataFrame:

dates = pd.date_range('20150101', periods=4)
df = pd.DataFrame({'A' : [5,10,3,4]}, index = dates)

df.loc[:,'B'] = 0
df.loc[:,'C'] = 0
df.iloc[0,1]  = 10
df.iloc[0,2]  = 3

print df

Out[69]:

             A   B  C
2015-01-01   5  10  3
2015-01-02  10   0  0
2015-01-03   3   0  0
2015-01-04   4   0  0
Run Code Online (Sandbox Code Playgroud)

我要实现对列下面的逻辑BC:

  • B(k+1) = B(k) - A(k+1)
  • C(k+1) = B(k) + A(k+1)

我可以使用以下代码执行此操作:

for i in range (1, df.shape[0]): 
        df.iloc[i,1] = df.iloc[i-1,1] - df.iloc[i,0] 
        df.iloc[i,2] = df.iloc[i-1,1] + df.iloc[i,0] 
print df
Run Code Online (Sandbox Code Playgroud)

这给出了:

             A   B   C
2015-01-01   5  10   3
2015-01-02  10   0  20
2015-01-03   3  -3   3
2015-01-04   4  -7   1
Run Code Online (Sandbox Code Playgroud)

这是我正在寻找的答案.问题是当我将其应用于DataFrame具有大型数据集的数据集时,它运行缓慢.非常慢.有没有更好的方法来实现这一目标?

And*_*den 6

矢量化的一个技巧是将所有内容重写为cumsums.

In [11]: x = df["A"].shift(-1).cumsum().shift().fillna(0)

In [12]: x
Out[12]:
2015-01-01     0
2015-01-02    10
2015-01-03    13
2015-01-04    17
Name: A, dtype: float64

In [13]: df["B"].cumsum() - x
Out[13]:
2015-01-01    10
2015-01-02     0
2015-01-03    -3
2015-01-04    -7
dtype: float64

In [14]: df["B"].cumsum() - x + 2 * df["A"]
Out[14]:
2015-01-01    20
2015-01-02    20
2015-01-03     3
2015-01-04     1
dtype: float64
Run Code Online (Sandbox Code Playgroud)

注意:第一个值是特殊情况,因此您必须将其调整为3.


chr*_*isb 3

像这样的递归事物可能很难向量化。 numba通常可以很好地处理它们 - 如果您需要重新分发代码,cython可能是更好的选择,因为它会生成常规的 c 扩展,而无需额外的依赖项。

In [88]: import numba

In [89]: @numba.jit(nopython=True)
    ...: def logic(a, b, c):
    ...:     N = len(a)
    ...:     out = np.zeros((N, 2), dtype=np.int64)
    ...:     for i in range(N):
    ...:         if i == 0:
    ...:             out[i, 0] = b[i]
    ...:             out[i, 1] = c[i]
    ...:         else:
    ...:             out[i, 0] = out[i-1,0] - a[i]
    ...:             out[i, 1] = out[i-1,0] + a[i]
    ...:     return out

In [90]: logic(df.A.values, df.B.values, df.C.values)
Out[90]: 
array([[10,  3],
       [ 0, 20],
       [-3,  3],
       [-7,  1]], dtype=int64)

In [91]: df[['A','B']] = logic(df.A.values, df.B.values, df.C.values)
Run Code Online (Sandbox Code Playgroud)

编辑:如其他答案所示,这个问题实际上可以矢量化,您可能应该使用它。