Ссылка на ячейку фрейма данных pandas, фильтрация на основе определенного значения

#pandas #indexing

Вопрос:

Мне нужно получить ссылку на ячейку (строка #, столбец #) для всех областей в моем фрейме данных pandas, который содержит значение == 1.

 import pandas as pd
import numpy as np

df = pd.DataFrame({'x': [np.nan, 1, np.nan, np.nan, 1],
                   'y': [np.nan, np.nan, np.nan, np.nan, 1],
                   'z': [1, np.nan, 1, np.nan, np.nan]})
 

Хотите получить окончательный фрейм данных с двумя столбцами: row amp; col, который выглядит как:

   row  col
0  1    1
1  4    1
2  4    2
3  0    3
4  2    3
 

Ответ №1:

Вы можете использовать numpy.argwhere .

Это должно быть намного быстрее, чем все решения for , использующие df.stack цикл, и т.д. Пожалуйста, смотрите тайминги ниже:

 In [145]: import numpy as np

In [146]: res = pd.DataFrame(np.argwhere(df.notnull().values).tolist(), columns=['row', 'col'])

In [147]: res.col = res.col   1

In [148]: res
Out[148]: 
   row  col
0    0    3
1    1    1
2    2    3
3    4    1
4    4    2
 

Тайминги:

np.argwhere :

 In [149]: %timeit pd.DataFrame(np.argwhere(df.notnull().values).tolist(), columns=['row', 'col'])
437 µs ± 4.71 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
 

решение @sophocles с использованием df.stack :

 In [151]: %timeit pd.DataFrame(df[df.notna()].stack().index.tolist(),columns=['row','col'])
1.33 ms ± 5.55 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
 

Ответ №2:

Вы можете использовать notna() , чтобы вернуть логический фрейм данных и stack() удалить те nan , в которые были преобразованы False . Возьмите index и преобразуйте в список, чтобы вы могли легко конвертировать в фрейм данных.

Обертывание этого в a pd.DataFrame() с правильными именами столбцов дает вам то, что вам нужно:

 df.columns=[1,2,3]
pd.DataFrame(df[df.notna()].stack().index.tolist(),columns=['row','col'])
 

    row  col
0    0    3
1    1    1
2    2    3
3    4    1
4    4    2
 

Ответ №3:

Вы можете просто перебирать строки и столбцы:

 res_df = pd.DataFrame(columns=['row', 'col'])

for i in range(len(df)):
  for j in range(len(df.columns)):
    if df[df.columns[j]].iloc[i] == 1:
      res_df = res_df.append({'row': i, 'col': j 1}, ignore_index=True)

print(res_df.sort_values(by='col').reset_index(drop=True))
 
   row col
0   1   1
1   4   1
2   4   2
3   0   3
4   2   3
 

Ответ №4:

Вы можете попробовать это:

 import pandas as pd
import numpy as np

df = pd.DataFrame({'x': [np.nan, 1, np.nan, np.nan, 1],
                   'y': [np.nan, np.nan, np.nan, np.nan, 1],
                   'z': [1, np.nan, 1, np.nan, np.nan]})

list_indexes = []
for idx in range(len(df.columns)):
    rows = df.index[df.iloc[:, idx] == 1].tolist()
    for row in rows:
        list_indexes.append((row, idx 1))

final = pd.DataFrame(list_indexes, columns=['row', 'column'])
print(final)
 

Ответ №5:

Вы можете сделать это:

 df.columns=list(range(1,len(df.columns) 1))

   1    2   3
0   NaN NaN 1.0
1   1.0 NaN NaN
2   NaN NaN 1.0
3   NaN NaN NaN
4   1.0 1.0 NaN
 
 new_df = df.stack().reset_index().rename(columns = {'level_0':'row', 'level_1':'col'})[['row', 'col']]

   row  col
0    0    3
1    1    1
2    2    3
3    4    1
4    4    2