2016-12-26 59 views
2

我在Python中有以下數據框(按產品商店和周組合(排序)多個行)。根據最後出現次數計算前面的零數

product store week visit prob 
123  321 1 0  0.003 
123  321 2 0  0.234 
123  321 3 1  0 
123  321 4 0  0.198 
123  301 1 0  0.290 
123  301 2 2  0 
123  301 3 0  0.989 
123  301 4 4  0.788 

我想根據訪問列中前面的零的數量找到累積概率。例如:對於每個產品商店周的組合,我會發現第一次出現訪問> 0。然後計算前面的零的數量。然後乘以prob列中的所有行,直到我的值大於0並且該產品商店組合的最後一週。像下面的東西。對於> 0的訪問,cum_prob可以留空或用0代替。

product store week visit prob cum_prob 
123  321 1 0  0.003 0.000702 
123  321 2 0  0.234 0.000702 
123  321 3 1  0 
123  321 4 0  0.198 0.198 
123  301 1 0  0.290 0.290 
123  301 2 2  0 
123  301 3 0  0.989 0.989 
123  301 4 4  0.788 

如何在Python中實現此目的?在SAS中,我可以使用數組和一些循環。

回答

2

我將創建一個工作數據集d1併爲其分配一些新列。

  • iszero跟蹤其中prob爲零。稍後我會乘以此列
  • novist跟蹤我們visit不是零的軌道。稍後我將乘以此值並用它來幫助創建組
  • filled_prob填充1其中prob爲零。這有助於使我的prod函數稍後運行良好。

d1 = df.assign(
    iszero=df.prob.eq(0), 
    novisit=df.visit.ne(0), 
    filled_prob=np.where(df.prob.eq(0), 1, df.prob) 
) 

d1 

enter image description here

我會用我剛剛創建創建一個分組列

d1['visit_group'] = d1.groupby(['product', 'store']).novisit.cumsum() 
d1 

enter image description here

最後一列,加'cum_prob'與我在上面製作的列。

d1['cum_prob'] = d1.groupby(
    ['product', 'store', 'visit_group'] 
).filled_prob.transform('prod') * (~d1.iszero) * (~d1.novisit) 
d1 

enter image description here


你可以切它爲您的目的

d1.loc[:, df.columns.tolist() + ['cum_prob']] 

enter image description here


一起

d1 = df.assign(
    iszero=df.prob.eq(0), 
    novisit=df.visit.ne(0), 
    filled_prob=np.where(df.prob.eq(0), 1, df.prob) 
) 
d1['visit_group'] = d1.groupby(['product', 'store']).novisit.cumsum() 
d1['cum_prob'] = d1.groupby(
    ['product', 'store', 'visit_group'] 
).filled_prob.transform('prod') * (~d1.iszero) * (~d1.novisit) 
d1.loc[:, df.columns.tolist() + ['cum_prob']] 

迴應置評:周跳

是否不改變的計算,因爲我已經奠定了。相反,我們可以預先篩選df這樣

def skip_weeks(x): 
    """check if difference in week from one row 
    to the next is always 1. If not, then we skipped a week""" 
    return x.week.diff().dropna().eq(1).all() 

# I'll use this to map and filter in a bit 
no_skips = df.groupby(['product', 'store']).apply(skip_weeks) 

# produces 
# product store 
# 123  301  True 
#   321  True 
# dtype: bool 

# simple series of tuples 
# could've done `df[['product', 'store']].apply(tuple, 1)` 
# but this is quicker 
s = pd.Series(list(zip(df['product'].tolist(), df.store.tolist())), df.index) 

# filter, this is what we then use rest of algorithm on 
# remember to assign it to a variable like `df = df.loc[s.map(no_skips)]` 
df.loc[s.map(no_skips)] 
+0

非常感謝,你能否解釋第二個最後一步。變換部分 – Mukul

+0

[transform](http://pandas.pydata.org/pandas-docs/stable/groupby.html#transformation)返回一個對象,該對象的相同索引傳遞給groupby組中的'groupby'複製值。 – piRSquared

+0

我真的不喜歡這個答案。非常複雜,難以遵循。 –

1

這裏是每星期都會分配到一個組,然後找到基於該組的累積和解決方案。

完成的第一件事就是將訪問次數變爲0/1,並使用s.ne(0)。然後,第一個差異將爲組中的第一行創建-1/1。然後對此進行絕對值的累加總和以創建組。然後,我們可以簡單地使用transform並採取每個組的產品。

df['group'] = df.groupby(['product', 'store'])['visit']\ 
       .transform(lambda s: s.ne(0).diff().abs().cumsum().fillna(0)) 

df['cum_prod'] = df.groupby(['product', 'store', 'group'])['prob']\ 
        .transform(lambda s: s.prod()) 

請參閱下面輸出中的組列。你必須做的一件事是讓所有非零訪問有0個概率,而最後一行沒有這個概率。

product store week visit prob group cum_prod 
0  123 321  1  0 0.003  0 0.000702 
1  123 321  2  0 0.234  0 0.000702 
2  123 321  3  1 0.000  1 0.000000 
3  123 321  4  0 0.198  2 0.198000 
4  123 301  1  0 0.290  0 0.290000 
5  123 301  2  2 0.000  1 0.000000 
6  123 301  3  0 0.989  2 0.989000 
7  123 301  4  4 0.788  3 0.788000 
+0

'df.loc [7,'cum_prod']'應該是零..我相信 – piRSquared