Première valeur non nulle par ligne à partir d'une liste de Pandas colonnes
Si j'ai un DataFrame dans les pandas qui ressemble à quelque chose comme:
A B C
0 1 NaN 2
1 NaN 3 NaN
2 NaN 4 5
3 NaN NaN NaN
Comment puis-je obtenir la première valeur non nulle à partir de chaque ligne? E. g. pour le haut, j'aimerais obtenir: [1, 3, 4, None]
(ou l'équivalent de la Série).
Vous devez vous connecter pour publier un commentaire.
C'est vraiment une manière désordonnée pour ce faire, utilisez d'abord
first_valid_index
pour obtenir la validité de colonnes, de convertir le retour de la série à un dataframe, nous pouvons donc appelerapply
ligne sage et index retour à l'original df:MODIFIER
Un peu le moyen le plus propre:
df
mondial ici me fait un peu mal au cœur. Vraiment, vous voulez une combinaison de @yangjie réponse et celle-ci. Je vais poster une combinaison, mais n'hésitez pas à voler les meilleurs morceaux (si vous pensez qu'il y a de tout!)Vous n'avez pas besoin de se compliquer la vie avec
first_valid_index
:Je vais peser ici car je pense que c'est une bonne affaire plus vite que les méthodes proposées.
argmin
donne l'indice de la premièreFalse
valeur dans chaque ligne du résultat denp.isnan
dans un vectorisé façon, qui est la partie la plus difficile. Il repose toujours sur une boucle Python pour extraire les valeurs, mais le look est très rapide:EDIT:
Voici une entièrement vectorisé solution qui est peut être une bonne affaire plus rapide encore en fonction de la forme de l'entrée. Mise à jour de l'analyse comparative ci-dessous.
Si une ligne est complètement nul, la valeur correspondante sera nulle également.
Voici quelques comparaisons avec les unutbu la solution:
%timeit get_frst_non_null(df)
Ici est une autre façon de faire:
L'idée ici est d'utiliser
stack
pour déplacer les colonnes dans une rangée niveau de l'indice:Maintenant, si vous groupe par la première ligne de niveau -- c'est à dire l'indice d'origine -- et prendre la première valeur de chaque groupe, vous avez essentiellement à obtenir le résultat souhaité:
Tout ce que nous devons faire est de revisiter le résultat (à l'aide de l'indice d'origine) afin de
inclure les lignes qui sont complètement NaN:
Ce n'est pas nouveau, mais c'est une combinaison des meilleurs morceaux de @yangie de l'approche avec une compréhension de liste, et @EdChum de
df.appliquer
approche que je pense est le plus facile à comprendre.Tout d'abord, les colonnes à nous voulons recevoir nos valeurs de?
Maintenant, comment choisit-on les valeurs?
C'est ok, mais nous voulons vraiment l'index pour correspondre à l'original
DataFrame
:pick_cols
pour le résultat final. Que serait cette opération doit être appelé en pensez-vous?first_valid_index
estNone
pour gérer la ligne avec tous lesNaN
sIci est une solution en ligne:
Edit:
Cette solution itère sur les lignes de
df
.row.first_valid_index()
étiquette de retour pour le premier non-NA/valeur null, ce qui sera utilisée comme index pour obtenir le non null premier élément de chaque ligne.Si il n'y a pas de valeur non null dans la ligne,
row.first_valid_index()
en aurait Aucun, ne peut donc pas être utilisé comme indice, j'ai donc besoin d'unif-else
déclaration.J'ai emballé le tout dans une compréhension de liste pour des raisons de concision.
first_valid_index()
deux fois. Peut-être que si vous perdez un peu de concision, vous gagnerez en lisibilité et en efficacité.first_valid_index()
deux fois aussi bien. Merci pour les conseils, je vais peut-être mettre à jour plus tard.JoeCondron réponse (EDIT: avant sa dernière édition!) c'est cool mais il y a de la marge pour une amélioration significative en évitant les non-vectorisé énumération:
L'amélioration est faible si le DataFrame est relativement plat:
... mais peut être sur un slim DataFrames:
Par rapport à JoeCondron est vectorisé version, le moteur d'exécution est très similaire (ce qui est encore légèrement plus rapide pour les slim DataFrames, et légèrement plus lent pour les grandes).
groupby
dansaxis=1
Si l'on fait passer un callable qui renvoie la même valeur, on regroupe toutes les colonnes. Cela nous permet d'utiliser
groupby.agg
qui nous donne lafirst
méthode qui rend ce facileCela renvoie d'un dataframe avec le nom de la colonne de la chose, j'étais de retour dans mon appelable
lookup
,notna
, etidxmax
argmin
et de tranchage