Неожиданное поведение от применения np.isin () к кадру данных pandas - PullRequest
1 голос
/ 24 мая 2019

Работая над ответом на другой вопрос , я наткнулся на неожиданное поведение:

Рассмотрим следующий фрейм данных:

df = pd.DataFrame({
    'A':list('AAcdef'),
    'B':[4,5,4,5,5,4],
    'E':[5,3,6,9,2,4],
    'F':list('BaaBbA')
})
print(df)
   A  B  E  F
0  A  4  5  B  #<— row contains 'A' and 5
1  A  5  3  a  #<— row contains 'A' and 5
2  c  4  6  a
3  d  5  9  B
4  e  5  2  b
5  f  4  4  A

Если мы попытаемся найти все столбцы, содержащие ['A', 5], мы можем использовать Jezrael's answer :

cond = [['A'],[5]]
print( np.logical_and.reduce([df.isin(x).any(1) for x in cond]) )

который (правильно) дает: [ True True False False False False]

Если мы, однако, используем:

cond = [['A'],[5]]
print( df.apply(lambda x: np.isin([cond],[x]).all(),axis=1) )

это дает:

0    False
1    False
2    False
3    False
4    False
5    False
dtype: bool

При ближайшем рассмотрении второй попытки выясняется, что:

  • np.isin(['A',5],df.loc[0]) "неправильно" дает array([ True, False]), вероятно, из-за numpy, выводящего dtype <U1, и, следовательно, 5!='5'
  • np.isin(['A',5],['A',4,5,'B']) "правильно" дает array([ True, True]), что означает, что мы можем (и должен ) использовать df.loc[0].values.tolist() в методе .apply() выше

Вопрос, упрощенно:

Зачем нужно для указания x.values.tolist() в одном случае, и я могу напрямую использовать x в другом?

print( np.logical_and.reduce([df.isin(x).any(1) for x in cond]) )
print( df.apply(lambda x: np.isin([cond],x.values.tolist()).all(),axis=1 ) )

Edit:

Еще хуже то, что происходит, если мы ищем [4,5]:

cond = [[4],[5]]
## this returns False for row 0
print( df.apply(lambda x: np.isin([cond],x.values.tolist() ).all() ,axis=1) )
## this returns True for row 0
print( df.apply(lambda x: np.isin([cond],x.values ).all() ,axis=1) )

Ответы [ 2 ]

2 голосов
/ 24 мая 2019

Я думаю, что в DataFrame смешанные числа с целочисленными столбцами, так что если цикл по строкам получит Series с типами смешивания, так что numpy приведите к strings.

Возможное решение - преобразовать в массив, а затемв string значения в cond:

cond = [[4],[5]]

print(df.apply(lambda x: np.isin(np.array(cond).astype(str), x.values.tolist()).all(),axis=1))
0     True
1    False
2    False
3    False
4    False
5    False
dtype: bool

К сожалению, для общего решения (если возможно, только числовые столбцы) необходимо преобразовать как - cond, так и Series:

f = lambda x: np.isin(np.array(cond).astype(str), x.astype(str).tolist()).all()
print (df.apply(f, axis=1))

Или все данные:

f = lambda x: np.isin(np.array(cond).astype(str), x.tolist()).all()
print (df.astype(str).apply(f, axis=1))

Если использовать наборы в чистом Python, все работает хорошо:

print(df.apply(lambda x: set([4,5]).issubset(x),axis=1) )
0     True
1    False
2    False
3    False
4    False
5    False
dtype: bool

print(df.apply(lambda x: set(['A',5]).issubset(x),axis=1) )
0     True
1     True
2    False
3    False
4    False
5    False
dtype: bool
0 голосов
/ 24 мая 2019

Потому что

  1. df.isin относится к pd.Series, а np.isin - нет.
  2. pd.loc возвращает pd.Series.
  3. Чтобы преобразовать pd.Series в массив, ваш x.values.tolist() должен работать.
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...