J'ai une base de données comportant 3 colonnes - A, B et projets. A et B contiennent les identifiants attribués à chaque élève d'une classe et les projets représentent le nombre de projets qu'ils ont réalisés ensemble. Les données sont au niveau de la colonne A et de la colonne B
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])
Remarque, un étudiant peut apparaître dans n'importe quelle colonne de l'ensemble de données d'entrée (S2 est à la fois en cola et colB) Maintenant, j'ai besoin de trouver le nombre de projets réalisés par un étudiant avec tous les autres étudiants. Le dataframe devrait ressembler à ceci
id_ | StudentB | projects S2 S3 5 S2 S5 1 S2 S4 2 S3 S2 5 S4 S2 2 S4 S5 1 S5 S4 1
Maintenant, si je filtre la colonne id_ pour un studentID particulier, tous les identifiants associés doivent être listés dans la colonne StudentB
My solution ('all_student_id' est une liste distincte de tous les identifiants possibles) -
A | B | projects S2 S3 5 S2 S4 2 S5 S2 1 S5 S4 1
Bien que je puisse le faire en utilisant une boucle for pour tous les identifiants d'élève distincts, je pense que ce n’est pas une solution évolutive puisque le jeu de données d’entrée peut être énorme (30 millions de lignes).
Toute aide à l’optimisation de cette solution sera appréciée
3 Réponses :
Vous pouvez faire:
# 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
L'idée est que si je filtre la colonne A pour S2, une liste de tous les élèves dont S2 a fait partie devrait être répertoriée, ce qui n'est pas le cas dans la solution que vous avez publiée (S2 est dans la colonne B de la ligne 2)
@ user3788040 l'a compris, apportant le changement
@ user3788040 vérifier maintenant
@YOLO votre mise à jour n'a pas changé le problème. Vous devez faire une sorte de recherche / tableau croisé pour obtenir toutes les combinaisons, pour le moment, vous ne regardez que la première colonne et la deuxième, et non l'inverse. Toutes les valeurs uniques doivent être représentées dans la première colonne en fonction de la question.
@ user3483203 pour moi, la sortie ne diffère qu'en ajoutant des lignes en double de la valeur du projet en interchangeant les valeurs A, B. Par ex. S2-S3-5, il y a une autre ligne pour S3-S2-5
Exactement, mais c'est ce qu'il demande.
Est-ce que cela fonctionnera?
Alors faites-moi savoir si cet exemple fonctionne comme vous le souhaitez:
0 1
S2 S3 5
S4 2
S5 7
S4 S5 1
Ce serait un peu comme:
f=np.sort(m.iloc[:,0:2].values) pd.concat((pd.DataFrame(f),m[['projects']]),axis=1).groupby([0,1])['projects'].sum()
Maintenant, ce que j'ai supposé, c'est que vous voulez, si jamais disons que S2 et S5 se réunissaient, que ce soit dans la colonne 1 ou la colonne 2, ils devraient être comptés comme l'inverse. Prenant cette liberté, j'ai effectué une analyse et j'ai obtenu ceci:
A B projects 0 S2 S3 5 1 S2 S4 2 2 S5 S2 1 3 S5 S4 1 4 S2 S5 6
Le résultat que j'ai obtenu était:
m=pd.DataFrame({'A':("S2","S2","S5","S5",'S2'),'B':("S3","S4","S2","S4",'S5'), 'projects':(5,2,1,1,6)})
Il renomme la colonne comme 0 et 1, qui peuvent être modifiés par set_axis. Le point principal est, est-ce que c'est comme ça que vous voulez? Que S2 et S5, quel que soit l'ordre, ont donné leur somme en sortie?
Les autres réponses recommandent groupby , mais à partir de la sortie souhaitée, je ne suis pas d'accord que ce soit ce que vous recherchez. Il semble que vous souhaitiez simplement que les relations de B-> A soient également incluses en tant que relations de A-> B . Il s'agit d'une opération triviale, qui peut être accomplie en empilant une version inversée des colonnes A et B
>>> lookp.loc['S2', 'S3'] 5 >>> lookp.loc['S3', 'S5'] nan
p>
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
Vous pouvez maintenant rechercher n'importe quel élève en utilisant uniquement la colonne id_ , bien que je recommande un pivot ici pour de meilleures données structure:
lookp = d.pivot('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
Cela vous donne un moyen facile de rechercher les relations des étudiants, avec un NaN indiquant que deux élèves n'ont travaillé ensemble sur aucun projet.
a = df.values b = a[:, [1,0,2]].copy() d = pd.DataFrame(np.vstack((a, b)), columns=['id_', 'StudentB', 'projects'])