Python Pandas: получить индекс строк, столбец которых соответствует определенному значению

278

Учитывая DataFrame со столбцом «BoolCol», мы хотим найти индексы DataFrame, в которых значения для «BoolCol» == True

В настоящее время у меня есть итеративный способ сделать это, который отлично работает:

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

Но это не правильный способ панды сделать это. После некоторых исследований я в настоящее время использую этот код:

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

Этот дает мне список индексов, но они не совпадают, когда я проверяю их, выполняя:

df.iloc[i]['BoolCol']

Результат на самом деле Ложь!

Какой будет правильный способ Панды сделать это?

Я хочу значки
источник

Ответы:

430

df.iloc[i]возвращает ithстроку df. iне относится к метке индекса, iэто индекс на основе 0.

Напротив, атрибут indexвозвращает фактические метки индекса , а не числовые индексы строк:

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

или эквивалентно,

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

Вы можете увидеть разницу достаточно четко, играя с DataFrame с индексом не по умолчанию, который не равен числовой позиции строки:

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]

Если вы хотите использовать индекс ,

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

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

тогда вы можете выбрать строки, используя locвместоiloc :

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

[3 rows x 1 columns]

Обратите внимание, что locтакже могут принимать логические массивы :

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

[3 rows x 1 columns]

Если у вас есть логический массив maskи вам нужны порядковые значения индекса, вы можете вычислить их, используяnp.flatnonzero :

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

Используйте df.ilocдля выбора строк по порядковому индексу:

In [113]: df.iloc[np.flatnonzero(df['BoolCol'])]
Out[113]: 
   BoolCol
10    True
40    True
50    True
unutbu
источник
9
Еще один способ сделать df.query('BoolCol').
Филлип Облако
3
Я знаю, что это старо, но мне интересно, есть ли простой способ получить индексные числа на основе 0 из запроса. Мне нужны цифры iloc, потому что я хочу выбрать несколько строк до и после ряда, удовлетворяющего определенному условию. Поэтому я планировал получить 0-индексы строк, удовлетворяющих условию, а затем создать срезы для использования в iloc (). Единственное, что я вижу, это get_loc, но он не может принимать массив.
Шерид
3
@sheridp: Если у вас есть логическая маска, вы можете найти порядковые индексы, где maskнаходится True, используя np.flatnonzero. Я отредактировал пост выше, чтобы показать, что я имею в виду.
unutbu
8
Ваше предложение indices = np.flatnonzero(df[col_name] == category_name)дает мне именно то, о чем говорится в заголовке вопроса, что на удивление трудно найти в Интернете.
ClimbsRocks
Если вы хотите вернуть только индекс, каковы издержки df [dftest] .index? Создает ли это промежуточный фрейм данных (данные которого могут быть гигабайтами). Как насчет dftest? Разве это также не выделяет очень большой промежуточный объект, где возвращаемый индекс может быть очень маленьким или даже пустым. Являются ли они волшебно оптимизированы, используя ленивые представления. Если нет, то наверняка должен быть эффективный путь.
user48956
31

Это можно сделать с помощью функции 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

Хотя вам не всегда нужен индекс для совпадения, но если вам нужно:

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
источник
2

Простой способ - сбросить индекс DataFrame перед фильтрацией:

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

Немного хак, но это быстро!

Бен Друитт
источник
1

Сначала вы можете проверить, queryкогда целевой столбец является типом bool (PS: о том, как его использовать, пожалуйста, проверьте ссылку )

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

После того, как мы отфильтруем исходный df по логическому столбцу, мы можем выбрать индекс.

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

Также панды есть nonzero, мы просто выбрать позицию в Trueстроке и использовать его Нарезать DataFrameилиindex

df.index[df.BoolCol.nonzero()[0]]
Out[128]: Int64Index([10, 40, 50], dtype='int64')
YOBEN_S
источник
1

Если вы хотите использовать объект dataframe только один раз, используйте:

df['BoolCol'].loc[lambda x: x==True].index
mbh86
источник
0

Я продлил этот вопрос , который , как получает row, columnи valueвсе ценности спичек?

вот решение:

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]

Вывод:

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


row  col        name
0    1           dog
2    0         Puppy
Carson
источник