2017-05-04 80 views
4

我可以問建議更有效地迭代(和更快)嗎? 這裏的問題,我正在尋找一種方式來在大熊貓數據幀確定窗口大小中傳播的零下來:尋找一個有效的方式來迭代

import numpy as np 
import pandas as pd 

A = np.matrix([[ 0., 1., 1., 1., 1.], 
      [ 1., 0., 1., 1., 1.], 
      [ 1., 1., 0., 1., 1.], 
      [ 1., 1., 1., 0., 1.], 
      [ 1., 1., 1., 1., 0.], 
      [ 1., 1., 1., 1., 1.], 
      [ 1., 1., 1., 1., 1.], 
      [ 1., 1., 1., 1., 1.], 
      [ 1., 1., 1., 1., 0.], 
      [ 1., 1., 0., 1., 1.], 
      [ 1., 1., 1., 1., 1.], 
      [ 1., 1., 1., 1., 1.], 
      [ 1., 1., 1., 1., 1.], 
      [ 1., 1., 1., 1., 1.], 
      [ 1., 1., 1., 0., 1.], 
      [ 1., 1., 1., 1., 1.], 
      [ 1., 1., 0., 1., 1.], 
      [ 1., 1., 1., 1., 0.], 
      [ 1., 0., 1., 1., 1.], 
      [ 1., 1., 1., 1., 1.]]) 

df = pd.DataFrame(A) 

現在我們要通過的3行,每行 從數值窗口的增量填補頂端。 3行的每個窗口開始於window_start,定義爲:

window_size = 3 
window_start = [i for i in range(0, df.shape[0]) 
       if i % window_size == 0] 
print(df) 
gf = df.copy() 
print('\n') 

現在使數據幀,其中零從該窗口內的 前述上面的行傳播:

for i in window_start: 
for j in range(1, window_size): 
    try: gf.iloc[i + j] = gf.iloc[i + j - 1] * gf.iloc[i + j] 
    except: pass 

print(gf) 

該最後位是相當對於非常大的數據集來說效率低下且耗時,是否有更好的方法來做到這一點?

回答

7

您應該可以通過groupby內的累積產品完成此任務。

df.groupby(np.arange(len(df)) // 3).cumprod() 

     0 1 2 3 4 
0 0.0 1.0 1.0 1.0 1.0 
1 0.0 0.0 1.0 1.0 1.0 
2 0.0 0.0 0.0 1.0 1.0 
3 1.0 1.0 1.0 0.0 1.0 
4 1.0 1.0 1.0 0.0 0.0 
5 1.0 1.0 1.0 0.0 0.0 
6 1.0 1.0 1.0 1.0 1.0 
7 1.0 1.0 1.0 1.0 1.0 
8 1.0 1.0 1.0 1.0 0.0 
9 1.0 1.0 0.0 1.0 1.0 
10 1.0 1.0 0.0 1.0 1.0 
11 1.0 1.0 0.0 1.0 1.0 
12 1.0 1.0 1.0 1.0 1.0 
13 1.0 1.0 1.0 1.0 1.0 
14 1.0 1.0 1.0 0.0 1.0 
15 1.0 1.0 1.0 1.0 1.0 
16 1.0 1.0 0.0 1.0 1.0 
17 1.0 1.0 0.0 1.0 0.0 
18 1.0 0.0 1.0 1.0 1.0 
19 1.0 0.0 1.0 1.0 1.0 

我們可以採取更好看,使用concat,看看它在做什麼,我們想要的東西。

pd.concat([df.iloc[:6, :2], d1.iloc[:6, :2]], axis=1, keys=['Before', 'After']) 

    Before  After  
     0 1  0 1 
0 0.0 1.0 0.0 1.0 
1 1.0 0.0 0.0 0.0 
2 1.0 1.0 0.0 0.0 
3 1.0 1.0 1.0 1.0 
4 1.0 1.0 1.0 1.0 
5 1.0 1.0 1.0 1.0 

我的上一個numpy辦法採取
見@ Divakar的解決方案,我借他的功能的一些元素

def prop_zero(df, window_size=3): 
    a = df.values 
    W = window_size 
    m, n = a.shape 

    pad = np.zeros((W - m % W, n)) 
    b = np.vstack([a, pad]) 

    return pd.DataFrame(
     b.reshape(-1, W, n).cumprod(1).reshape(-1, n)[:m], 
     df.index, df.columns 
    ) 

prop_zero(df) 
+1

注意,這將如果值溢出失敗,例如'[1e200,1e200,0]',因爲cumprod會產生'[1e200,inf,nan]'。 ;-) #unlikelyfailuremodeoftheday – DSM

+0

不錯的主題標籤:-) – piRSquared

5

你可以做一個groupbycummin

In [46]: out = df.groupby(np.arange(len(df))//3).cummin() 

In [47]: df.head(6) 
Out[47]: 
    0 1 2 3 4 
0 0.0 1.0 1.0 1.0 1.0 
1 1.0 0.0 1.0 1.0 1.0 
2 1.0 1.0 0.0 1.0 1.0 
3 1.0 1.0 1.0 0.0 1.0 
4 1.0 1.0 1.0 1.0 0.0 
5 1.0 1.0 1.0 1.0 1.0 

In [48]: out.head(6) 
Out[48]: 
    0 1 2 3 4 
0 0.0 1.0 1.0 1.0 1.0 
1 0.0 0.0 1.0 1.0 1.0 
2 0.0 0.0 0.0 1.0 1.0 
3 1.0 1.0 1.0 0.0 1.0 
4 1.0 1.0 1.0 0.0 0.0 
5 1.0 1.0 1.0 0.0 0.0 

這是假定所有的值是0和1.如果您有非1的值,但是你仍然要零後零的行爲,你可以不喜歡

df.where(~(df == 0).groupby(np.arange(len(df))//3).cummax(), 0) 

這是不一樣漂亮,但不會被0.5(如將cummin直接應用於值)或潛在溢出(如將cumprod直接應用於值)那樣的值混淆。

+0

只要值是1和0,它就可以工作。很好的答案! – piRSquared

+0

@piRSquared:好點,我應該使它更一般.. – DSM

4

下面是一個NumPy方法,它將第一個軸分割爲3D陣列,然後沿着第一個軸使用cumprod,然後重新變形回到2D。對於行數不能被window_size整除的情況,我們會有剩餘的元素,這些元素不會成爲整形的一部分,並且會被單獨處理。

因此,實現起來 -

def numpy_cumprod(df, window_size=3): 
    a = df.values 
    W = window_size 
    m,n = a.shape 
    N = m//W 
    M = N*W 

    out0 = a[:M].reshape(-1,W,n).cumprod(1).reshape(-1,n) 
    out = np.vstack((out0, a[M:].cumprod(0))) 
    return pd.DataFrame(out) 

採樣運行 - 對大數據集

In [279]: df 
Out[279]: 
    0 1 2 3 4 
0 2 2 2 0 1 
1 1 2 0 2 2 
2 1 1 0 0 1 
3 2 0 2 0 1 
4 0 0 0 1 0 
5 0 0 1 2 1 
6 1 1 0 0 1 
7 0 0 1 2 1 
8 2 2 2 1 1 
9 2 1 2 1 0 
10 1 1 1 1 2 
11 0 2 2 1 2 

In [280]: numpy_cumprod(df, window_size=3) 
Out[280]: 
    0 1 2 3 4 
0 2 2 2 0 1 
1 2 4 0 0 2 
2 2 4 0 0 2 
3 2 0 2 0 1 
4 0 0 0 0 0 
5 0 0 0 0 0 
6 1 1 0 0 1 
7 0 0 0 0 1 
8 0 0 0 0 1 
9 2 1 2 1 0 
10 2 1 2 1 0 
11 0 2 4 1 0 

運行測試 -

In [275]: df = pd.DataFrame(np.random.randint(0,3,(10000,5))) 

# @piRSquared's soln-1 using pandas groupby 
In [276]: %timeit df.groupby(np.arange(len(df)) // 3).cumprod() 
100 loops, best of 3: 2.49 ms per loop 

# @piRSquared's soln-2 using NumPy 
In [261]: %timeit prop_zero(df, window_size=3) 
1000 loops, best of 3: 285 µs per loop 

# Proposed in this post 
In [262]: %timeit numpy_cumprod(df, window_size=3) 
1000 loops, best of 3: 262 µs per loop 
+1

這就是我要添加的:-)我打算在最後追加一組填充零,然後再刪除它們。 – piRSquared

+0

@piRSquared可愛的加法在那裏,也添加到時間。現在很快。 – Divakar

相關問題