3
votes

Créer une colonne binaire dans le dataframe pandas en fonction de la priorité

J'ai un dataframe pandas qui ressemble à ceci:

Item    Status    Value
123     B         1
123     BW        0
123     W         0
123     NF        0
456     W         0
456     BW        1
789     W         1
789     NF        0
000     NF        1

Et je dois créer une nouvelle colonne Value qui sera soit 1 ou 0 selon les valeurs dans les colonnes Item et Status . L'attribution de la valeur 1 est priorisée par cet ordre: B , BW , W , NF . Donc, en utilisant l'exemple de dataframe ci-dessus, le résultat devrait être:

Item    Status
123     B
123     BW
123     W 
123     NF
456     W
456     BW
789     W
789     NF
000     NF

Utilisation de Python 3.7.


2 commentaires

Comment la colonne Item joue-t-elle un rôle à cet égard? Attribuez-vous une seule valeur 1 par Article , en fonction de l’ordre de priorité dans Statut ?


S'il n'y a qu'une seule instance d'un certain élément dans la colonne Item , elle doit être 1 par défaut. Cependant, lorsqu'il y a plus d'une occurrence d'un élément, alors, en fonction du Statut et de la priorité, il doit y avoir une valeur correspondante de 1 ou 0 . J'espère que cela a du sens.


3 Réponses :


0
votes

Je pourrais peut-être vous aider sur le plan conceptuel, en vous expliquant certaines étapes que je ferais:

  1. Créez la nouvelle valeur de colonne et remplissez-la de zéros np.zeros () ou pd.fillna()
  2. Regroupez le dataframe par élément avec groupby = pd.groupby ('Item')
  3. Parcourir tous les groupes trouvés pour le nom, grouper dans groupby:
  4. En utilisant une fonction simple avec if, une file d'attente de priorité personnalisée, des critères de tri personnalisés ou toute autre méthode préférée, déterminez quelle entrée a la priorité la plus élevée " par cette valeur 1 est priorisé par cet ordre: B, BW, W, NF ", et attribuer une valeur de 1 à sa colonne Valeur group.loc [entrée] ['Valeur'] == 0

    Disons que nous examinons le groupe "123":

     Item    Status    Value
     -------------------------
     123     B         0 (before 0, after 1)
     123     BW        0
     123     W         0
     123     NF        0
    

    Étant donné que la ligne [123, 'B', 0] avait la priorité la plus élevée en fonction de vos critères, vous la remplacez par [123, 'B', 1] code >

  5. Une fois terminé, recréez le dataframe à partir de l'objet groupby, et vous avez terminé. Vous avez beaucoup de possibilités pour le faire, peut-être vérifier ici: Conversion d'un Pandas GroupBy objecter à DataFrame


0 commentaires

2
votes

En prenant votre dataframe d'origine comme dataframe d'entrée df , le code suivant produira la sortie souhaitée:

#dictionary assigning order of priority to status values
priority_map = {'B':1,'BW':2,'W':3,'NF':4}

#new temporary column that converts Status values to order of priority values
df['rank'] = df['Status'].map(priority_map)

#create dictionary with Item as key and lowest rank value per Item as value
lowest_val_dict = df.groupby('Item')['rank'].min().to_dict()

#new column that assigns the same Value to all rows per Item
df['Value'] = df['Item'].map(lowest_val_dict)

#replace Values where rank is different with 0's
df['Value'] = np.where(df['Value'] == df['rank'],1,0)

#delete rank column
del df['rank']


0 commentaires

1
votes

Je préférerais une approche où le statut est un ordre pd.Categorical , car a) c'est ce que c'est et b) c'est beaucoup plus lisible: si vous avez cela, vous comparez simplement si une valeur est égale au max de son groupe:

df['Status'] = pd.Categorical(df['Status'], categories=['NF', 'W', 'BW', 'B'],
                              ordered=True)
df['Value'] = df.groupby('Item')['Status'].apply(lambda x: (x == x.max()).astype(int))

#   Item Status  Value
#0   123      B      1
#1   123     BW      0
#2   123      W      0
#3   123     NF      0
#4   456      W      0
#5   456     BW      1
#6   789      W      1
#7   789     NF      0
#8     0     NF      1


2 commentaires

Le dernier devrait être meilleur par df ['Value'] = df.groupby ('Item') ['Status']. Transform ('max'). Eq (df ['Status'‌]). Astype ( int)


Vous pourriez le considérer mieux, car il est un peu plus rapide pour les très grandes trames de données, même si je dirais qu'il est moins lisible. Bref, bon commentaire, approche intéressante