web-dev-qa-db-fra.com

Récupère l'index d'une ligne d'un pandas dataframe sous forme d'entier

Supposons un dataframe facile, par exemple

    A         B
0   1  0.810743
1   2  0.595866
2   3  0.154888
3   4  0.472721
4   5  0.894525
5   6  0.978174
6   7  0.859449
7   8  0.541247
8   9  0.232302
9  10  0.276566

Comment puis-je récupérer une valeur d'index d'une ligne, étant donné une condition? Par exemple: dfb = df[df['A']==5].index.values.astype(int) renvoie [4], mais ce que j'aimerais obtenir, c'est simplement 4. Cela me cause des ennuis plus tard dans le code.

En fonction de certaines conditions, je souhaite disposer d’un enregistrement des index pour lesquels cette condition est remplie, puis sélectionner des lignes entre elles.

J'ai essayé

dfb = df[df['A']==5].index.values.astype(int)
dfbb = df[df['A']==8].index.values.astype(int)
df.loc[dfb:dfbb,'B']

pour une sortie désirée

    A         B
4   5  0.894525
5   6  0.978174
6   7  0.859449

mais je reçois TypeError: '[4]' is an invalid key

30
durbachit

Le plus simple est add _[0]_ - sélectionnez la première valeur de la liste avec un élément:

_dfb = df[df['A']==5].index.values.astype(int)[0]
dfbb = df[df['A']==8].index.values.astype(int)[0]
_

_dfb = int(df[df['A']==5].index[0])
dfbb = int(df[df['A']==8].index[0])
_

Mais si possible, certaines valeurs ne correspondent pas, une erreur est générée, car la première valeur n'existe pas.

La solution est d'utiliser next avec iter pour obtenir le paramètre par défaut si les valeurs ne correspondent pas:

_dfb = next(iter(df[df['A']==5].index), 'no match')
print (dfb)
4

dfb = next(iter(df[df['A']==50].index), 'no match')
print (dfb)
no match
_

Il semble alors nécessaire de soustraire _1_:

_print (df.loc[dfb:dfbb-1,'B'])
4    0.894525
5    0.978174
6    0.859449
Name: B, dtype: float64
_

Une autre solution avec boolean indexing ou query :

_print (df[(df['A'] >= 5) & (df['A'] < 8)])
   A         B
4  5  0.894525
5  6  0.978174
6  7  0.859449

print (df.loc[(df['A'] >= 5) & (df['A'] < 8), 'B'])
4    0.894525
5    0.978174
6    0.859449
Name: B, dtype: float64
_

_print (df.query('A >= 5 and A < 8'))
   A         B
4  5  0.894525
5  6  0.978174
6  7  0.859449
_
39
jezrael

Pour répondre à la question initiale sur l'obtention de l'index sous forme d'entier pour la sélection souhaitée, voici ce qui fonctionne:

df[df['A']==5].index.item()
26
dmdip

La nature de vouloir inclure la ligne où A == 5 et toutes les lignes jusqu'à mais pas , y compris la ligne où A == 8 signifie que nous allons finissez par utiliser iloc (loc inclut les deux extrémités de la tranche).

Afin d'obtenir les étiquettes d'index, nous utilisons idxmax. Cela retournera la première position de la valeur maximale. Je lance ceci sur une série booléenne où A == 5 (puis lorsque A == 8) qui renvoie la valeur d'index de lorsque A == 5 se produit pour la première fois (même chose pour A == 8).

Ensuite, j'utilise searchsorted pour trouver la position ordinale de l'emplacement de l'étiquette d'index (que j'ai trouvée ci-dessus). C'est ce que j'utilise dans iloc.

i5, i8 = df.index.searchsorted([df.A.eq(5).idxmax(), df.A.eq(8).idxmax()])
df.iloc[i5:i8]

enter image description here


numpy

vous pouvez encore améliorer cela en utilisant les objets numpy sous-jacents, les fonctions analogues de numpy. Je l'ai enveloppé dans une fonction pratique.

def find_between(df, col, v1, v2):
    vals = df[col].values
    mx1, mx2 = (vals == v1).argmax(), (vals == v2).argmax()
    idx = df.index.values
    i1, i2 = idx.searchsorted([mx1, mx2])
    return df.iloc[i1:i2]

find_between(df, 'A', 5, 8)

enter image description here


chronométrage
enter image description here

5
piRSquared