我有一个包含3列的数据框-A,B和项目。 A和B包含给班级中每个学生的ID,并且项目是他们一起完成的#of个项目。数据位于A列和B列的级别
A | B | projects
S2 S3 5
S2 S4 2
S5 S2 1
S5 S4 1
请注意,学生可以出现在输入数据集中的任何列中(S2在cola和colB中) 现在,我需要找到一个学生与其他所有学生一起完成的项目数量。数据框应该看起来像这样
id_ | StudentB | projects
S2 S3 5
S2 S5 1
S2 S4 2
S3 S2 5
S4 S2 2
S4 S5 1
S5 S4 1
现在,如果我过滤特定学生ID的ID_列,则所有相关ID都应列在StudentB列中
我的解决方案(“ all_student_id”是所有可能ID的不同列表)-
final_df = pd.DataFrame(columns = ['id_', 'studentB','projects'])
for id_ in all_student_id:
data_ = data[(data['A']== id_) | (data['B']== id_)]
a = data_[['A','projects']].rename(columns= {'A':'studentB'})
b = data_[['B','projects']].rename(columns= {'B':'studentB'})
a_b_concat = pd.concat([a,b], axis=0)
formatted = a_b_concat[a_b_concat['studentB']!=id_]
temp = pd.DataFrame({'id_':[id_]*formatted.shape[0]
})
temp = pd.concat([temp, formatted.reset_index(drop = True)], axis = 1)
final_df= pd.concat([final_df, temp])
虽然我能够对所有不同的学生ID使用for循环来实现此目的,但我相信这不是可伸缩的解决方案,因为输入数据集可能非常庞大(3000万行)。
在优化此解决方案方面的任何帮助将不胜感激
答案 0 :(得分:1)
您可以这样做:
# sort the students - create a new data frame
df1 = df[['A','B']]
df1.values.sort(axis=1)
df1['projects'] = df['projects']
# now groupb
df1.groupby(['A','B'])['projects'].sum().reset_index()
A B projects
0 S2 S3 5
1 S2 S4 2
2 S2 S5 1
3 S4 S5 1
答案 1 :(得分:0)
这项工作可以吗?
因此,请让我知道此示例是否按您想要的方式工作:
m=pd.DataFrame({'A':("S2","S2","S5","S5",'S2'),'B':("S3","S4","S2","S4",'S5'), 'projects':(5,2,1,1,6)})
这有点像:
A B projects
0 S2 S3 5
1 S2 S4 2
2 S5 S2 1
3 S5 S4 1
4 S2 S5 6
现在我想假设的是,如果您想让S2和S5一起出现在第1列或第2列中,那么它们应该算作反之亦然。出于这种自由,我进行了一些分析并得出以下结论:
f=np.sort(m.iloc[:,0:2].values)
pd.concat((pd.DataFrame(f),m[['projects']]),axis=1).groupby([0,1])['projects'].sum()
我得到的输出是:
0 1
S2 S3 5
S4 2
S5 7
S4 S5 1
将列重命名为0和1,可以通过set_axis对其进行更改。要点是,这是您想要的吗? S2和S5,无论顺序如何,都将其总和作为输出?
答案 2 :(得分:0)
其他答案建议使用groupby
,但从您期望的输出来看,我不同意这是您正在寻找的东西。似乎您只是希望将来自B->A
的关系也包含为来自A->B
的关系。这是一个微不足道的操作,可以通过堆叠列A
和B
的反向版本来完成
a = df.values
b = a[:, [1,0,2]].copy()
d = pd.DataFrame(np.vstack((a, b)), columns=['id_', 'StudentB', 'projects'])
id_ StudentB projects
0 S2 S3 5
1 S2 S4 2
2 S5 S2 1
3 S5 S4 1
4 S3 S2 5
5 S4 S2 2
6 S2 S5 1
7 S4 S5 1
现在,您可以只使用id_
列查找任何学生,尽管我建议在此处使用pivot
以获得更好的数据结构:
lookp = d.pivot('id_', 'StudentB', 'projects')
StudentB S2 S3 S4 S5
id_
S2 NaN 5 2 1
S3 5 NaN NaN NaN
S4 2 NaN NaN 1
S5 1 NaN 1 NaN
这为您提供了一种查找学生关系的简便方法,其中NaN
表示两个学生没有一起从事任何项目。
>>> lookp.loc['S2', 'S3']
5
>>> lookp.loc['S3', 'S5']
nan