2016-12-26 60 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