您可以像这样使用explode 来展平您的数据框:
#generating data
df = pd.DataFrame([
['pid-1', 'June', '| Product Id| |PROD1| |PROD2|'],
['pid-2', 'July', '| Product Id| |PROD1| |PROD2| |PROD3|']
], columns = ['Promotion ID', 'Month', 'Products'])
# extracting the product list
df['Products'] = df['Products']\
.apply(lambda s: [x for x in re.split(' *\| *', s) if x != '' and x != 'Product Id'])
exploded_df = exploded_df = df.explode('Products', ignore_index=True)
此时df 和exploded_df 看起来像这样:
# df
Promotion ID Month Products
0 pid-1 June [PROD1, PROD2]
1 pid-2 July [PROD1, PROD2, PROD3]
# exploded_df
Promotion ID Month Products
0 pid-1 June PROD1
1 pid-1 June PROD2
2 pid-2 July PROD1
3 pid-2 July PROD2
4 pid-2 July PROD3
我会停在那里。恕我直言,只保留第一行的 Month 和 Promotion ID 的值只会让你更喜欢。然而,既然你问了,你可以使用rank 和loc 将None 分配给不是第一个组的所有行:
# rank needs a numeric column
exploded_df['index'] = exploded_df.index
# using rank to create a filter on rows that are not the first of their group
filter = exploded_df\
.groupby(['Promotion ID'])['index']\
.rank('dense').apply(lambda x: x > 1)
# getting rid of the index column
exploded_df = exploded_df.drop('index', axis=1)
# and voila
exploded_df.loc[filter, ['Month', 'Promotion ID']] = None
结果:
Promotion ID Month Products
0 None None PROD1
1 pid-1 June PROD2
2 None None PROD1
3 pid-2 July PROD2
4 pid-2 July PROD3