Панды: Найдите строку, содержащую несколько значений, произвольно распределенных по столбцам

#python #python-3.x #pandas

Вопрос:

Я ищу хорошее решение следующей проблемы: у меня есть фрейм данных pandas, из которого я знаю только, что одна из строк содержит несколько значений, произвольно распределенных по столбцам. Я бы хотел найти этот ряд.

Пример: Оба следующих двух кадра данных имеют ровно одну строку, содержащую значения «эй», «здесь» и «Я есть».:

 df = pd.DataFrame({"a": (np.nan, 1, "hey", 5, 100), "b": ("testing", np.nan, "here", "what", -3),
                   "c": (1, "two", 3, "four", 5), "d": ("ay", "why", "I am", np.nan, 4)})

 
 df:
     a        b     c     d
0  NaN  testing     1    ay
1    1      NaN   two   why
2  hey     here     3  I am
3    5     what  four   NaN
4  100       -3     5     4
 

В строке df 2 (третья строка) содержатся значения «эй», «здесь» и «Я есть».

 df2 = pd.DataFrame({"a": (np.nan, 1, np.nan, 5, "I am"), "b": ("testing", np.nan, "something", "what", -3),
                    "c": (1, "two", 3, "four", "hey"), "d": ("ay", "why", "I am", np.nan, "here")})
 
 df2:
      a          b     c     d
0   NaN    testing     1    ay
1     1        NaN   two   why
2   NaN  something     3  I am
3     5       what  four   NaN
4  I am         -3   hey  here

 

В df2 строка 4 (пятая строка) содержит значения «эй», «здесь» и «Я есть».

Как мне получить индекс строки соответствующей строки, содержащей значения? Мое решение работает, но оно уродливо:

 row_id = [id for id, row in df.iterrows() if hasattr(row, "str") and
          (row.str.contains("hey").sum()  
           row.str.contains("here").sum()  
           row.str.contains("I am").sum() == 3)][0]
 

Я думаю, что должно быть более приятное и более питоническое решение этой проблемы.

Ответ №1:

Вот питонический способ подойти к проблеме. Замаскируйте значения , которых нет в списке l , затем используйте nunique по оси столбцов для подсчета уникальных значений и сравнения с 3 ними, чтобы создать логическую маску

 l = ['hey', 'here', 'I am']
s = df.where(df.isin(l)).nunique(axis=1).eq(3)
 

 print(s)
0    False
1    False
2     True
3    False
4    False
dtype: bool

print(s[s].index)
Int64Index([2], dtype='int64')