另一种方法
第一组BookID 和list all authors per book (i.e. list all authors per group)
combos = df.groupby('BookID').agg(lambda x: list(x)).reset_index(drop=False)
print(combos)
BookID Author
0 1 [John, Alex, Jenna]
1 2 [John, Alex]
2 3 [John]
3 4 [Alex, Mary, Max]
接下来,与 BookID 上的主要数据合并,以获取每个作者的所有作者
merged = combos.merge(df, how='inner', on='BookID')
print(merged)
BookID Author_x Author_y
0 1 [John, Alex, Jenna] John
1 1 [John, Alex, Jenna] Alex
2 1 [John, Alex, Jenna] Jenna
3 2 [John, Alex] John
4 2 [John, Alex] Alex
5 3 [John] John
6 4 [Alex, Mary, Max] Alex
7 4 [Alex, Mary, Max] Mary
8 4 [Alex, Mary, Max] Max
Author_x 是完整的作者列表,包括Author_y。现在可以使用以下方法将完整作者列表 (Author_x) 与每个个人/唯一作者 (Author_y) 进行比较
-
Create dict whose keys are unique
Author_y values(即唯一作者)和值是空白列表
- 遍历dict中的每个键值对
- 使用
Author_y 列从上述步骤中分割合并的数据帧;这会在 dict 键中为作者提供所有作者
- 从切片中,获取所有作者的列表 (
Author_x) 作为扁平列表
-
extend blank list 和 difference between flattened list (all authors) and dict key
d = {auth:[] for auth in df['Author'].unique()}
for k,v in d.items():
all_auths = merged[merged['Author_y']==k]['Author_x'].values.tolist()
auths = [coauths for nested in all_auths for coauths in nested]
v.extend(list(set(auths) - set([k])))
最后,放入DataFrame,统计每行的非空值
cnames = ['coauth'+str(k) for k in range(1,len(d))]
df_summary = pd.DataFrame.from_dict(d, orient='index', columns=cnames)
df_summary['Num_Unique_CoAuthors'] = df_summary.shape[1] - df_summary.isna().sum(axis=1)
print(df_summary)
author coauth1 coauth2 coauth3 coauth4 Num_Unique_CoAuthors
0 John Alex Jenna None None 2
1 Alex Max John Mary Jenna 4
2 Jenna John Alex None None 2
3 Mary Max Alex None None 2
4 Max Alex Mary None None 2
扩展数据案例
如果主要数据包含单个作者(即没有任何共同作者),则此方法为该行打印零
这是一个添加到数据中的虚拟行,只有一个作者
print(df)
BookID Author
0 1 John
1 1 Alex
2 1 Jenna
3 2 John
4 2 Alex
5 3 John
6 4 Alex
7 4 Mary
8 4 Max
9 5 Tom
这是输出
author coauth1 coauth2 coauth3 coauth4 Num_Unique_CoAuthors
0 John Jenna Alex None None 2
1 Alex Mary John Jenna Max 4
2 Jenna John Alex None None 2
3 Mary Max Alex None None 2
4 Max Mary Alex None None 2
5 Tom None None None None 0
初步回答
您是否尝试过 groupby 和 sum 聚合
df.groupby(['Author'])['BookID'].sum()