Я новичок в использовании фреймов данных Pandas, но много использовал фреймы данных Spark. Рассмотрим следующий фрейм данных.
Name Value Title
mickey 20 wonderland
donald 10 welcome to donald's castle
minnie 86 Minnie mouse clubhouse
Я хочу сохранить только те строки, где «Имя» содержится в «Заголовке», игнорируя регистр. Итак, в этом случае отфильтрованный фрейм данных должен выглядеть так
Name Value Title
donald 10 welcome to donald's castle
minnie 86 Minnie mouse clubhouse
Строка с Name = mickey была удалена.
В искре я могу создать фрейм данных df, а затем сказать df.filter($'Title'.lower().contains($'Name'.lower()))
Есть ли простой способ выразить это в кадрах данных Pandas?






Строковые методы в pandas по своей природе трудно векторизовать. Я обычно делаю это, используя понимание списка:
df[[y.lower() in x.lower() for x, y in zip(df['Title'], df['Name'])]]
Name Value Title
1 donald 10 welcome to donald's castle
2 minnie 86 Minnie mouse clubhouse
Большинство строковых методов можно ускорить с помощью понимания списков, если вы не беспокоитесь о NaN и смешанных типах. См. Для петель с пандами - когда мне нужно заботиться?.
Если вам нужна обработка ошибок, используйте функцию с обработкой try-except. Это на все еще быстрее.
def try_check(x, y):
try:
return y.lower() in x.lower()
except AttributeError:
return False
df[[try_check(x, y) for x, y in zip(df['Title'], df['Name'])]]
Name Value Title
1 donald 10 welcome to donald's castle
2 minnie 86 Minnie mouse clubhouse
@Nik pandas не «уродливый» :-), нам просто нужно следовать правильной логике, стоящей за этим.
Использование numpy.core.chararray
s1=df.Title.str.upper().values.astype(str)
s2=df.Name.str.upper().values.astype(str)
df[np.core.chararray.find(s1,s2)!=-1]
Out[790]:
Name Value Title
1 donald 10 welcome to donald's castle
2 minnie 86 Minnie mouse clubhouse
Вот еще одно решение, но оно использует метод .apply, не знаю, как это работает с точки зрения скорости, но это работает, и его довольно легко выразить.
df[df.apply(lambda x: x.Name.upper() in x.Title.upper(), axis=1) == True]
# Output
Name Value Title
1 donald 10 welcome to donald's castle
2 minnie 86 Minnie mouse clubhouse
Вот еще несколько вариантов, все основаны на этот ТАК пост (главное требование — использовать "|".join(...))
df_match = df.query("Title.str.lower().str.contains('|'.join(Name.str.lower()))")
print(df_match)
Name Value Title
1 donald 10 welcome to donald's castle
2 minnie 86 Minnie mouse clubhouse
print(df[df['Title'].str.lower().str.contains('|'.join(df['Name'].str.lower()))])
Name Value Title
1 donald 10 welcome to donald's castle
2 minnie 86 Minnie mouse clubhouse
вариант 3 — с использованием NumPy where
from numpy import where
df['match'] = (
where(df.Title.str.lower().str.contains(
'|'.join(df['Name'].str.lower()))
, True, False)
)
print(df[df['match']==True])
Name Value Title match
1 donald 10 welcome to donald's castle True
2 minnie 86 Minnie mouse clubhouse True
Вау! Панды серьезно ограничены в плане выразительности. Исходя из мира Spark, манипуляции Pandas DF выглядят почти безобразно. Спасибо за решение, хотя. Это выглядит хорошо. Примет решение.