熊猫列基于其他列中的值

时间:2018-08-02 22:13:48

标签: python pandas csv dataframe pandas-groupby

基本上,我想在“ Discount_Sub_Dpt”列中填入“是”或“否”,具体取决于那一周该Sub_Dpt是否有折扣,但该行所登陆的产品除外(例如,我不想A行中的任何行都可以考虑该周A是否有折扣,而仅考虑该子部门中的产品(在大多数情况下,其他产品不止一个)。

我尝试将groupby与Sub_Dpt和Week一起使用无济于事。

有人知道如何解决此问题吗?

“黄色”列显然是代码的理想结果。

CSV Example

这是我使用过的一些代码,我试图先创建该列,然后更新值(但可能都错了)(也有意将其命名为数据帧df1):

  df1['Discount_Sub_Dpt'] = np.where((df1['Discount']=='Yes'),'Yes','No')

 grps = []                    
 grps.append(df1.Sub_Dpt.unique())
 for x in grps:
      x = str(x)
      yes_weeks = df1.loc[(df1.Discount_SubDpt == 'Yes') & (df1.Sub_Dpt_Description == x),'Week'].unique()        
  df1.loc[df1['Week'].isin(yes_weeks) & df1['Sub_Dpt_Description'] == x, 'Discount_SubDpt'] = 'Yes'

4 个答案:

答案 0 :(得分:1)

好的,这可能无法很好地扩展,但应该易于阅读。

df1 = pd.DataFrame(data= [[ 'A',    1,  'Toys', 'Yes',  ],
[   'A',    2,  'Toys', 'No',   ],
[   'A',    3,  'Toys', 'No',   ],
[   'A',    4,  'Toys', 'Yes',  ],
[   'B',    1,  'Toys', 'No',   ],
[   'B',    2,  'Toys', 'Yes',  ],
[   'B',    3,  'Toys', 'No',   ],
[   'B',    4,  'Toys', 'Yes',  ],
[   'C',    1,  'Candy',    'No',   ],
[   'C',    2,  'Candy',    'No',   ],
[   'C',    3,  'Candy',    'Yes',  ],
[   'C',    4,  'Candy',    'Yes',  ],
[   'D',    1,  'Candy',    'No',   ],
[   'D',    2,  'Candy',    'No',   ],
[   'D',    3,  'Candy',    'No',   ],
[   'D',    4,  'Candy',    'No',   ],], columns=['Product', 'Week', 'Sub_Dpt',        'Discount'])
df2 = df1.set_index(['Product', 'Week', 'Sub_Dpt'])
products = df1.Product.unique()
df1['Discount_SubDpt'] = df1.apply(lambda x: 'Yes' if 'Yes' in df2.loc[(list(products[products != x['Product']]), x['Week'], x['Sub_Dpt']), 'Discount'].tolist() else 'No', axis=1)

第一步是创建一个Multindex数据框。

接下来,我们获得所有产品的列表

接下来,对于每一行,我们在同一周和子部门取出并删除产品。

在此列表中,如果有折扣,我们选择“是”,否则选择“否”

编辑1:

如果您不想创建另一个数据框(节省内存,但是会慢一些)

df1['Discount_SubDpt'] = df1.apply(lambda x: 'Yes' if 'Yes' in df1.loc[(df1['Product'] != x['Product']) & (df1['Week'] == x['Week']) & (df1['Sub_Dpt'] == x['Sub_Dpt']), 'Discount'].tolist() else 'No', axis=1)

答案 1 :(得分:1)

好吧,以下内容有些疯狂,但是效果很好,所以请听。

首先,我们将按照以下步骤构建一个NetworkX图。

import networkx as nx
import numpy as np
import pandas as pd
G = nx.Graph()
Prods = df.Product.unique()
G.add_nodes_from(Prods)

现在,只要它们属于相同的sub_dpt,就在节点(所有产品)之间添加边。在这种情况下,由于A和B共享一个部门,而C和D共享一个部门,因此我们添加了边AB和CD。如果我们在同一部门中有ABC,我们将添加AB,AC,BC。我知道令人困惑,但请相信我。

G.add_edges_from([('A','B'),('C','D')])

现在是有趣的部分。我们需要将“折扣”列从“是/否”转换为“ 1/0”。

df['Disc2']=np.nan
df.loc[df['Discount']=='Yes','Disc2']=1
df.loc[df['Discount']=='No','Disc2']=0

现在我们旋转数据

tab = df.pivot(index = 'Week',columns='Product',values = 'Disc2')

现在,我们这样做

tab = pd.DataFrame(np.dot(tab,nx.adjacency_matrix(G,Prods).todense()), columns=Prods,index=df.Week.unique())
tab[0].astype(bool)
df = df.merge(tab.unstack().reset_index(),left_on=['Product','Week'],right_on=['level_0','level_1'])
df['Discount_Sub_Dpt']=df[0]
print(df[['Product','Week','Sub_Dpt','Discount','Discount_Sub_Dpt']])

您可能会问,为什么会遇到这种麻烦?好吧,两个原因。首先,它要稳定得多。其他答案不能解决问题的所有可能情况。其次,它比其他解决方案快得多。希望对您有所帮助!

答案 2 :(得分:1)

仅当折扣为“是”时,您才可以执行GroupBy('Week', 'Sub_Dpt')映射到'Product'的列表。

然后使用清单推导来检查是否有折扣产品存在问题。最后,将布尔序列结果映射到“是” /“否”。

来自@SahilPuri的数据。

# GroupBy only when Discount == Yes
g = df1[df1['Discount'] == 'Yes'].groupby(['Week', 'Sub_Dpt'])['Product'].unique()

# calculate index by row
idx = df1.set_index(['Week', 'Sub_Dpt']).index

# construct list of Booleans according to criteria
L = [any(x for x in g.get(i, []) if x!=j) for i, j in zip(idx, df1['Product'])]

# map Boolean to strings
df1['Discount_SubDpt'] = pd.Series(L).map({True: 'Yes', False: 'No'})

print(df1)

   Product  Week Sub_Dpt Discount Discount_SubDpt
0        A     1    Toys      Yes              No
1        A     2    Toys       No             Yes
2        A     3    Toys       No              No
3        A     4    Toys      Yes             Yes
4        B     1    Toys       No             Yes
5        B     2    Toys      Yes              No
6        B     3    Toys       No              No
7        B     4    Toys      Yes             Yes
8        C     1   Candy       No              No
9        C     2   Candy       No              No
10       C     3   Candy      Yes              No
11       C     4   Candy      Yes              No
12       D     1   Candy       No              No
13       D     2   Candy       No              No
14       D     3   Candy       No             Yes
15       D     4   Candy       No             Yes

答案 3 :(得分:0)

已经晚了,但是可以走了。我在上面的注释中使用了样本df。

df1['dis'] = df1['Discount'].apply(lambda x: 1 if x =="Yes" else 0)
df2 = df1.groupby(['Sub_Dpt','Week']).sum()
df2.reset_index(inplace = True)
df3 = pd.merge(df1,df2, left_on=['Sub_Dpt','Week'], right_on =['Sub_Dpt','Week'])
df3['Discount_Sb_Dpt'] = np.where(df3['dis_x'] < df3['dis_y'], 'Yes', 'No')
df3.sort_values(by=['Product'], inplace = True)
df3