table/df 列之间的反向分组关系
Reverse grouping relationship between table/df columns
假设我的 df 是:
index "A" "B"
0 A1 "B1,B2,B3"
1 A2 "B2,B4,B3"
2 A3 "B2,B3,B5"
我想做 magical_function(df)
index "B'" "A''"
0 B1 "A1"
1 B2 "A1,A2,A3"
2 B3 "A1,A2,A3"
3 B4 "A2"
4 B5 "A3"
所以我使用了爆炸策略(所有优点都在这里发帖:pandas: How do I split text in a column into multiple rows?)
因此,我首先 dropna 以避免错误,然后我用要拆分的列创建一个系列,我分解它并堆叠它,然后具有相同索引的连接魔术在需要的地方复制 "A" 列值
dcolumn="A"
col="B"
current_wdf=df[[idcolumn,col]].dropna()
current_col=current_wdf.loc[:,col]
exploded_df=current_col.str.split(',').apply(pd.Series,1).stack()#much slower but keep the index. I could used substitution with enumerate after dropping level
exploded_df.index=exploded_df.index.droplevel(-1)
exploded_df.name=col
agg_df=pd.DataFrame(current_wdf.loc[:,idcolumn]).join(exploded_df)
grouped=agg_df.groupby([col])
在我拥有的之后:
0 1
0 B1 A1
1 B2 A1
1 B2 A2
1 B2 A3
2 B3 A1
2 B3 A2
2 B3 A3
3 B4 A2
4 B5 A3
那我就
grouped=agg_df.groupby([col])
gives
a dict
{'B1': Int64Index([0], dtype='int64'),
'B2': Int64Index([1, 1, 1], dtype='int64'),
'B3': Int64Index([2, 2, 2], dtype='int64'),
'B4': Int64Index([3], dtype='int64'),
'B5': Int64Index([4], dtype='int64')}
要获得我想要的数据框,我需要克服 "groups" 仅显示索引的限制并执行此操作
groups_dict= {k: list(grouped.get_group(v).loc[:,idcolumn]) for k, v in grouped.groups.items()}
或
agg_df2=agg_df.reset_index()
groups_dict2= {k: list(agg_df2.loc[v,idcolumn]) for k,v in grouped.indices.items()}
我终于有了数据框,但感觉都很慢。
但这不是微不足道的,我对最后一部分持怀疑态度。
可以用,但是速度慢,而且很容易坏。
这样的匹配反转过程没有操作吗?
而且,对于像我公开的组内容检索,有什么方法可以获取内容而不是索引而不必重复执行 get_group?
使用set_index
+ str.split
+ stack
+ groupby
+ apply
+ reset_index
:
df = df.set_index('A')['B']
.str.split(',', expand=True)
.stack()
.reset_index(name='B')
.groupby('B')['A']
.apply(', '.join)
.reset_index()
print (df)
B A
0 B1 A1
1 B2 A1, A2, A3
2 B3 A1, A2, A3
3 B4 A2
4 B5 A3
另一种使用 numpy.concatenate
+ numpy.repeat
+ DataFrame
构造函数的解决方案:
s = df.set_index('A')['B'].str.split(',')
l = s.str.len()
df1 = pd.DataFrame({'A': np.repeat(df['A'].values, l), 'B':np.concatenate(s)})
df1 = df1.groupby('B')['A'].apply(', '.join).reset_index()
print (df1)
B A
0 B1 A1
1 B2 A1, A2, A3
2 B3 A1, A2, A3
3 B4 A2
4 B5 A3
假设我的 df 是:
index "A" "B"
0 A1 "B1,B2,B3"
1 A2 "B2,B4,B3"
2 A3 "B2,B3,B5"
我想做 magical_function(df)
index "B'" "A''"
0 B1 "A1"
1 B2 "A1,A2,A3"
2 B3 "A1,A2,A3"
3 B4 "A2"
4 B5 "A3"
所以我使用了爆炸策略(所有优点都在这里发帖:pandas: How do I split text in a column into multiple rows?)
因此,我首先 dropna 以避免错误,然后我用要拆分的列创建一个系列,我分解它并堆叠它,然后具有相同索引的连接魔术在需要的地方复制 "A" 列值
dcolumn="A"
col="B"
current_wdf=df[[idcolumn,col]].dropna()
current_col=current_wdf.loc[:,col]
exploded_df=current_col.str.split(',').apply(pd.Series,1).stack()#much slower but keep the index. I could used substitution with enumerate after dropping level
exploded_df.index=exploded_df.index.droplevel(-1)
exploded_df.name=col
agg_df=pd.DataFrame(current_wdf.loc[:,idcolumn]).join(exploded_df)
grouped=agg_df.groupby([col])
在我拥有的之后:
0 1
0 B1 A1
1 B2 A1
1 B2 A2
1 B2 A3
2 B3 A1
2 B3 A2
2 B3 A3
3 B4 A2
4 B5 A3
那我就
grouped=agg_df.groupby([col])
gives
a dict
{'B1': Int64Index([0], dtype='int64'),
'B2': Int64Index([1, 1, 1], dtype='int64'),
'B3': Int64Index([2, 2, 2], dtype='int64'),
'B4': Int64Index([3], dtype='int64'),
'B5': Int64Index([4], dtype='int64')}
要获得我想要的数据框,我需要克服 "groups" 仅显示索引的限制并执行此操作
groups_dict= {k: list(grouped.get_group(v).loc[:,idcolumn]) for k, v in grouped.groups.items()}
或
agg_df2=agg_df.reset_index()
groups_dict2= {k: list(agg_df2.loc[v,idcolumn]) for k,v in grouped.indices.items()}
我终于有了数据框,但感觉都很慢。
但这不是微不足道的,我对最后一部分持怀疑态度。 可以用,但是速度慢,而且很容易坏。
这样的匹配反转过程没有操作吗? 而且,对于像我公开的组内容检索,有什么方法可以获取内容而不是索引而不必重复执行 get_group?
使用set_index
+ str.split
+ stack
+ groupby
+ apply
+ reset_index
:
df = df.set_index('A')['B']
.str.split(',', expand=True)
.stack()
.reset_index(name='B')
.groupby('B')['A']
.apply(', '.join)
.reset_index()
print (df)
B A
0 B1 A1
1 B2 A1, A2, A3
2 B3 A1, A2, A3
3 B4 A2
4 B5 A3
另一种使用 numpy.concatenate
+ numpy.repeat
+ DataFrame
构造函数的解决方案:
s = df.set_index('A')['B'].str.split(',')
l = s.str.len()
df1 = pd.DataFrame({'A': np.repeat(df['A'].values, l), 'B':np.concatenate(s)})
df1 = df1.groupby('B')['A'].apply(', '.join).reset_index()
print (df1)
B A
0 B1 A1
1 B2 A1, A2, A3
2 B3 A1, A2, A3
3 B4 A2
4 B5 A3