基本上,我想在“ Discount_Sub_Dpt”列中填入“是”或“否”,具体取决于那一周该Sub_Dpt是否有折扣,但该行所登陆的产品除外(例如,我不想A行中的任何行都可以考虑该周A是否有折扣,而仅考虑该子部门中的产品(在大多数情况下,其他产品不止一个)。
我尝试将groupby与Sub_Dpt和Week一起使用无济于事。
有人知道如何解决此问题吗?
“黄色”列显然是代码的理想结果。
这是我使用过的一些代码,我试图先创建该列,然后更新值(但可能都错了)(也有意将其命名为数据帧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'
答案 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