Pandy Pythona: Uzyskaj indeks wierszy, których kolumna odpowiada określonej wartości

274

Biorąc pod uwagę DataFrame z kolumną „BoolCol”, chcemy znaleźć indeksy DataFrame, w których wartości dla „BoolCol” == True

Obecnie mam iteracyjny sposób, aby to zrobić, co działa idealnie:

for i in range(100,3000):
    if df.iloc[i]['BoolCol']== True:
         print i,df.iloc[i]['BoolCol']

Ale to nie jest właściwy sposób, aby to zrobić panda. Po kilku badaniach aktualnie używam tego kodu:

df[df['BoolCol'] == True].index.tolist()

Ten daje mi listę indeksów, ale nie pasują one, gdy sprawdzam je, wykonując:

df.iloc[i]['BoolCol']

Wynik jest w rzeczywistości False !!

Jaki byłby właściwy sposób, aby to zrobić?

Chcę odznaki
źródło

Odpowiedzi:

427

df.iloc[i]zwraca ithwiersz df. inie odnosi się do etykiety indeksu, ijest indeksem 0.

Natomiast atrybut indexzwraca rzeczywiste etykiety indeksów , a nie numeryczne indeksy wierszy:

df.index[df['BoolCol'] == True].tolist()

lub równoważnie

df.index[df['BoolCol']].tolist()

Różnicę widać dość wyraźnie, grając z DataFrame z domyślnym indeksem, który nie jest równy numerycznej pozycji wiersza:

df = pd.DataFrame({'BoolCol': [True, False, False, True, True]},
       index=[10,20,30,40,50])

In [53]: df
Out[53]: 
   BoolCol
10    True
20   False
30   False
40    True
50    True

[5 rows x 1 columns]

In [54]: df.index[df['BoolCol']].tolist()
Out[54]: [10, 40, 50]

Jeśli chcesz użyć indeksu ,

In [56]: idx = df.index[df['BoolCol']]

In [57]: idx
Out[57]: Int64Index([10, 40, 50], dtype='int64')

następnie możesz wybrać wiersze za pomocą loczamiastiloc :

In [58]: df.loc[idx]
Out[58]: 
   BoolCol
10    True
40    True
50    True

[3 rows x 1 columns]

Zauważ, że locakceptuje również tablice boolowskie :

In [55]: df.loc[df['BoolCol']]
Out[55]: 
   BoolCol
10    True
40    True
50    True

[3 rows x 1 columns]

Jeśli masz tablicę boolowską maski potrzebujesz wartości indeksu porządkowego, możesz je obliczyć za pomocąnp.flatnonzero :

In [110]: np.flatnonzero(df['BoolCol'])
Out[112]: array([0, 3, 4])

Użyj, df.ilocaby wybrać wiersze według indeksu porządkowego:

In [113]: df.iloc[np.flatnonzero(df['BoolCol'])]
Out[113]: 
   BoolCol
10    True
40    True
50    True
unutbu
źródło
9
Jeszcze innym sposobem jest zrobienie tego df.query('BoolCol').
Phillip Cloud,
3
Wiem, że to stare, ale zastanawiam się, czy istnieje prosty sposób na uzyskanie liczb indeksu opartych na 0 z zapytania. Potrzebuję liczb iloc, ponieważ chcę wybrać niektóre wiersze przed i po wierszu spełniającym określony warunek. Więc moim planem było uzyskanie 0-rzędów wierszy spełniających warunek, a następnie utworzenie wycinków do użycia w iloc (). Jedyne, co widzę, to get_loc, ale nie może przyjąć tablicy.
sheridp 21.04.2016
3
@sheridp: Jeśli masz maskę logiczną, możesz znaleźć indeksy porządkowe tam, gdzie maskjest True, używając np.flatnonzero. Zredagowałem powyższy post, aby pokazać, co mam na myśli.
unutbu
8
Twoja sugestia indices = np.flatnonzero(df[col_name] == category_name)daje mi dokładnie to, o co pyta tytuł pytania, co jest zaskakująco trudne do znalezienia w Internecie.
ClimbsRocks
Jeśli chcesz tylko cofnąć indeks, jaki jest narzut df [dftest] .index? Czy tworzy to pośrednią ramkę danych (której danymi mogą być gibabajty). Co z dftest? Czy to również nie przydziela bardzo dużego obiektu pośredniego, w którym zwracany indeks może być bardzo mały, a nawet pusty. Czy są one magicznie zoptymalizowane przy użyciu leniwych widoków. Jeśli nie, to na pewno musi być skuteczny sposób.
user48956,
31

Można to zrobić za pomocą funkcji numpy where ():

import pandas as pd
import numpy as np

In [716]: df = pd.DataFrame({"gene_name": ['SLC45A1', 'NECAP2', 'CLIC4', 'ADC', 'AGBL4'] , "BoolCol": [False, True, False, True, True] },
       index=list("abcde"))

In [717]: df
Out[717]: 
  BoolCol gene_name
a   False   SLC45A1
b    True    NECAP2
c   False     CLIC4
d    True       ADC
e    True     AGBL4

In [718]: np.where(df["BoolCol"] == True)
Out[718]: (array([1, 3, 4]),)

In [719]: select_indices = list(np.where(df["BoolCol"] == True)[0])

In [720]: df.iloc[select_indices]
Out[720]: 
  BoolCol gene_name
b    True    NECAP2
d    True       ADC
e    True     AGBL4

Chociaż nie zawsze potrzebujesz indeksu dla dopasowania, ale zwiększ, jeśli potrzebujesz:

In [796]: df.iloc[select_indices].index
Out[796]: Index([u'b', u'd', u'e'], dtype='object')

In [797]: df.iloc[select_indices].index.tolist()
Out[797]: ['b', 'd', 'e']
Surya
źródło
2

Prostym sposobem jest zresetowanie indeksu DataFrame przed filtrowaniem:

df_reset = df.reset_index()
df_reset[df_reset['BoolCol']].index.tolist()

Trochę hacky, ale jest szybki!

Ben Druitt
źródło
1

Najpierw możesz sprawdzić, querykiedy kolumna docelowa jest typu bool (PS: o tym, jak z niej korzystać, sprawdź link )

df.query('BoolCol')
Out[123]: 
    BoolCol
10     True
40     True
50     True

Po przefiltrowaniu oryginalnego pliku df według kolumny logicznej możemy wybrać indeks.

df=df.query('BoolCol')
df.index
Out[125]: Int64Index([10, 40, 50], dtype='int64')

Również pandy mają nonzero, po prostu wybrać pozycję z Truerzędu i wykorzystuje je pokroić DataFramelubindex

df.index[df.BoolCol.nonzero()[0]]
Out[128]: Int64Index([10, 40, 50], dtype='int64')
YOBEN_S
źródło
1

Jeśli chcesz użyć obiektu ramki danych tylko raz, użyj:

df['BoolCol'].loc[lambda x: x==True].index
mbh86
źródło
0

I rozszerzył to pytanie, które jest jak dostaje row, columni valuewszelkiej wartości meczów?

oto rozwiązanie:

import pandas as pd
import numpy as np


def search_coordinate(df_data: pd.DataFrame, search_set: set) -> list:
    nda_values = df_data.values
    tuple_index = np.where(np.isin(nda_values, [e for e in search_set]))
    return [(row, col, nda_values[row][col]) for row, col in zip(tuple_index[0], tuple_index[1])]


if __name__ == '__main__':
    test_datas = [['cat', 'dog', ''],
                  ['goldfish', '', 'kitten'],
                  ['Puppy', 'hamster', 'mouse']
                  ]
    df_data = pd.DataFrame(test_datas)
    print(df_data)
    result_list = search_coordinate(df_data, {'dog', 'Puppy'})
    print(f"\n\n{'row':<4} {'col':<4} {'name':>10}")
    [print(f"{row:<4} {col:<4} {name:>10}") for row, col, name in result_list]

Wynik:

          0        1       2
0       cat      dog        
1  goldfish           kitten
2     Puppy  hamster   mouse


row  col        name
0    1           dog
2    0         Puppy
Carson
źródło