1
votes

Fusion de champs similaires basés sur des lignes - Python

Bien que je sois capable de créer des tableaux croisés dynamiques dans Excel, j'aimerais utiliser Python pour finalement combiner des lignes avec des champs similaires. Dans ce cas, la ligne doit être combinée avec les mêmes "id" et "location" uniquement.

Entrée:

id  location1     location2   date      code1    code2
111 Park          Beach       1/1/2018  7765     7534
143 School                    2/5/2018  3345
223 Library                   3/5/2018  3345

Sortie 1:

id  location      date      code
111 Park, Beach   1/1/2018  7765, 7534
143 School        2/5/2018  3345
223 Library       3/5/2018  3345

Sortie 2:

id  location    date        code
111 Park        1/1/2018    7765
143 School      2/5/2018    3345
111 Beach       1/1/2018    7534
223 Library     3/5/2018    3345

La seule raison pour laquelle je voudrais comprendre les requêtes pour les deux sorties est parce que j'ai plusieurs autres colonnes avec des définitions pour ces codes. Je sais que je devrais utiliser l'ID et l'emplacement groupby, cependant, j'ai des difficultés avec la fusion dans la sortie 1 et avec la sortie 2 avec la création des nouvelles lignes.


2 commentaires

S'agit-il d'un dataframe pandas? vous souhaitez également combiner par id et date , n'est-ce pas?


Correct, pandas df. Et je ne voudrais combiner que si id et date sont les mêmes.


4 Réponses :


1
votes

IIUC,

mapper = lambda x : ",".join(x)
df["code"] = df["code"].astype(str)    
df.groupby("id").agg({"location" : mapper, "code" : mapper})

         location         code
id                            
111      Park,Beach     7765,7534
143        School         3345
223       Library         3345


0 commentaires

1
votes

Essayez ceci:

df['date'] = pd.to_datetime(df['date'])
df['code'] = df['code'].astype(str)
df = df.groupby(by=['id', 'date'], as_index=False).agg({'location': ','.join, 'code': ','.join})
print(df)

    id       date    location       code
0  111 2018-01-01  Park,Beach  7765,7534
1  143 2018-02-05      School       3345
2  223 2018-03-05     Library       3345


0 commentaires

1
votes

Vous pouvez essayer ceci:

Approche 1

Rejoignez les colonnes nécessaires dans dataframe

output2 = output1["location"].str.split(pat=",",expand=True)
output2.columns = ["location_"+ str(i) for i in output2.columns] 
output3 = output1["code"].str.split(pat=",",expand=True)
output3.columns = ["code"+ str(i) for i in output3.columns] 
final_output = pd.concat([output1, output2, output3],axis=1)
final_output = final_output.fillna('')

Approche 2

Dans cette approche, si la personne A va à l'école deux fois le même jour, la sortie prendra des valeurs uniques comme école au lieu d'afficher école, école . En même temps, disons que la personne A va à l'école deux fois le même jour mais a deux codes différents, puis elle produit les deux School,School

df["code"] = df["code"].astype(str)
output1 = df.groupby(["id","date"]).agg({"location": list,"code":list}).reset_index()

## check location and code having same set of unique values, will be performing `set` operation take unique elements
unique_values = output1[output1["location"].apply(set).apply(len) == output1["code"].apply(set).apply(len)]
## check location and code having different set of unique values, this case, might have same location with two different dates,
## no need to take `set` operation for this
other_values = output1[output1["location"].apply(set).apply(len) != output1["code"].apply(set).apply(len)]

## convert to set to , separated
unique_values["location"] = unique_values["location"].apply(set).apply(",".join)
unique_values["code"] = unique_values["code"].apply(set).apply(",".join)

other_values["location"] = other_values["location"].apply(",".join)
other_values["code"] = other_values["code"].apply(",".join)

## join both the dataframe
output1 = pd.concat([unique_values, other_values]).sort_index()

cela produit output1 dataframe

entrez la description de l'image ici

Le code ci-dessous sert à agrandir l'emplacement et la colonne code dans dataframe,

df["code"] = df["code"].astype(str)
output1 = df.groupby("id").agg({"location": ",".join,"code":",".join,"date":'first'}).reset_index()

Le résultat final est

 entrez la description de l'image ici


3 commentaires

Une question, comment adapteriez-vous le code pour éviter que le même emplacement ne soit répété deux fois? Par exemple, si la personne A se rend à l'école deux fois le même jour, la sortie affiche École, École . Je voudrais que cela apparaisse comme École uniquement dans ce cas. Cependant, disons que la personne A va à l'école deux fois le même jour mais a deux codes différents. Ensuite, la sortie devrait être École, École. Merci d'avance!


De plus, je remarque des doublons dans le sens où la personne A se rend au Parc, École ou École, Parc Y a-t-il un ordre par opération que je devrais utiliser pour m'assurer que ne se produit pas?


@Logan, j'ai mis à jour la solution. Pour supprimer les doublons, vous devrez peut-être effectuer drop_duplicates . Mais, j'ai géré la situation où la personne va à l ' école deux fois le même jour avec des codes différents.



1
votes

Pour CASE 1, DataFrame.groupby sur id et date puis agréger la colonne location et code à l'aide de .join : XXX

Pour CASE 2, utilisez DataFrame.melt , puis utilisez DataFrame.groupby sur id et variable et utilisez une transformation en utilisant cumcount pour ajouter un compteur séquentiel à la colonne variable , enfin utiliser .set_index , unstack , droplevel .

# CASE 1: print(df1)
    id      date     location        code
0  111  1/1/2018  Park, Beach  7765, 7534
1  143  2/5/2018       School        3345
2  223  3/5/2018      Library        3345

# CASE 2: print(df2)
variable   id      date code1 code2 location1 location2
0         111  1/1/2018  7765  7534      Park     Beach
1         143  2/5/2018  3345   NaN    School       NaN
2         223  3/5/2018  3345   NaN   Library       NaN

Résultat:

df2 = df.melt(id_vars=['id', 'date'])
df2['variable'] += df2.groupby(['id', 'variable']).cumcount().add(1).astype(str)
df2 = df2.set_index(['id', 'date', 'variable']).unstack().droplevel(0, 1).reset_index()


0 commentaires