3
votes

Faire correspondre les valeurs de plusieurs colonnes dans un ID

Exemple de DF:

 ID     Match1     Match2        Match3     Match4    Match5 Final_Match
    1      Yes      No            Yes        Yes      Yes     Clear
    2      Yes      No            Yes        Yes      No      Unclear
    2      Yes      No            No         Yes      Yes     Unclear
    3      No       Yes           Yes        Yes      No      Clear
    3      No       Yes           No         No       No      Unclear
    4      Yes      No            Yes        No       No      Unclear
    4      Yes      No            Yes        Yes      Yes     Clear

DF attendu:

ID     Match1        Match2        Match3     Match4       Match5
1      Yes           No            Yes        Yes          Yes
2      Yes           No            Yes        Yes          No
2      Yes           No            No         Yes          Yes
3      No            Yes           Yes        Yes          No
3      No            Yes           No         No           No
4      Yes           No            Yes        No           No
4      Yes           No            Yes        Yes          Yes

Énoncé du problème:

  1. Si l'ID n'est pas répétitif, insérez simplement Clear dans la colonne Final_Match (exemple d'ID 1)
  2. Si les ID sont répétitifs, dans un nombre d'ID Oui dans les colonnes Match1 à Match5, selon celui qui a le plus grand "Oui", mettez Clear pour celui-ci et Pas clair pour l'autre (ID d'exemple 3 et 4

  3. Si les ID sont répétitifs, alors dans un nombre d'ID Oui dans les colonnes Match1 à Match5, s'ils ont égal "Oui", insérez Unclear dans les deux (Exemple ID 2)

Je n'ai rien trouvé sur la façon de résoudre dans ID?


0 commentaires

3 Réponses :


1
votes

Utilisation de pandas.DataFrame.groupby:

final_match = []
for i, d in df.groupby('ID'):
    if len(d) == 1:
        final_match.append('Clear')
    else:
        counter = (d.filter(like='Match') == 'Yes').sum(1)
        if counter.nunique() == 1:
            final_match.extend(['Unclear'] * len(d))
        else:
            final_match.extend(counter.apply(lambda x: 'Clear' if x == max(counter) else 'Unclear').tolist())
df['final_match'] = final_match

print(df)
   ID Match1 Match2 Match3 Match4 Match5 final_match
0   1    Yes     No    Yes    Yes    Yes       Clear
1   2    Yes     No    Yes    Yes     No     Unclear
2   2    Yes     No     No    Yes    Yes     Unclear
3   3     No    Yes    Yes    Yes     No       Clear
4   3     No    Yes     No     No     No     Unclear
5   4    Yes     No    Yes     No     No     Unclear
6   4    Yes     No    Yes    Yes    Yes       Clear

Explication:

  • len (d) == 1 : si non répétitif, ajoutez Clear
  • counter = (d.filter (like = 'Match') == 'Yes'). sum (1) : Compte le nombre de 'Yes' dans chaque colonne
  • counter.nunique () == 1 : si toutes les lignes ont le même nombre de "Oui", alors toutes sont marquées comme "Pas clair"
  • counter.apply (lambda x: 'Clear' if x == max (counter) else 'Unclear'). tolist () : si les lignes ont des nombres différents de 'Yes', marquez le le plus élevé avec "Clear", reste avec "Unclear"


1 commentaires

Le problème est que l'ID ne vient qu'une seule fois.Lorsque je lance une partie du code, le dernier_match affiche Clear mais lorsque j'exécute tout le code, il remplace Clear par Unclear



2
votes

Une autre façon de procéder serait:

df['sum_yes']=df.iloc[:,1:6].eq('Yes').sum(axis=1)
df['final']=df.groupby('ID')['sum_yes'].transform\
             (lambda x: np.where((x==x.max())&(~x.duplicated(keep=False)),'Clear','Unclear'))
print(df)

   ID Match1 Match2 Match3 Match4 Match5  sum_yes    final
0   1    Yes     No    Yes    Yes    Yes        4    Clear
1   2    Yes     No    Yes    Yes     No        3  Unclear
2   2    Yes     No     No    Yes    Yes        3  Unclear
3   3     No    Yes    Yes    Yes     No        3    Clear
4   3     No    Yes     No     No     No        1  Unclear
5   4    Yes     No    Yes     No     No        2  Unclear
6   4    Yes     No    Yes    Yes    Yes        4    Clear

PS Vous pouvez supprimer la colonne sum_yes si vous le souhaitez. p >


2 commentaires

Si j'ai des colonnes entre ces colonnes de correspondance ou toute autre colonne à gauche ou à droite des colonnes Match d'actualités, dois-je modifier la partie iloc [:, 1: 6] ?


@RahulAgarwal oui, alors vous pouvez utiliser la méthode filter () et comme = Match comme le montre la solution de Chris. :)



2
votes

Vous pouvez également y parvenir en utilisant Groupby.rank:

# Helper Series
s = (df.replace({'Yes': 1, 'No': 0})
     .iloc[:, 1:]
     .sum(1))

df['final_match'] = np.where(s.groupby(df['ID']).rank(ascending=False).eq(1), 'Clear', 'Unclear')


10 commentaires

J'essaie maintenant votre solution en mettant deux colonnes dans Group by conditions, j'obtiens un "Key error" bien que j'aie ces deux colonnes par dataframe


pouvez-vous publier votre déclaration groupby ici?


np.where (s.groupby (df ['Supplier_Name_Translated', 'Spent']). r‌ ank (ascending = False) ‌ .eq (1), 'Full Match', 'Partial Match') < / code>


Le changement est que ce n'est plus par colonne "ID" comme auparavant mais par deux autres colonnes, dont l'une est du texte et l'autre des nombres


Essayé, donne cette erreur ValueError: Grouper pour '' pas unidimensionnel


Vous avez cette erreur TypeError: les objets 'Series' sont mutables, ils ne peuvent donc pas être hachés


Désolé, j'ai mal tapé la dernière suggestion, pouvez-vous essayer: np.where (s.groupby ([df ['Supplier_Name_Translated'], df ['Spent']]). Rank (ascending = False) .eq (1), 'Correspondance complète', 'Correspondance partielle') ?


Ma colonne Spent était une chaîne flottante, j'ai également converti en int. mais toujours une nouvelle erreur TypeError: l'objet 'NoneType' n'est pas appelable


Y a-t-il des NaN dans Spent maintenant?


J'ai vérifié ça, il n'y a pas de 'NaN' ou de blancs d'ailleurs