我有一个看起来像这样的数据框
item1 = {'category':'food::cafe::restaurant::business', 'name':'Bob Cafe'}
item2 = {'category':'food::take away::restaurant::business', 'name':'John Take Away'}
item3 = {'category':'cafeteria::business', 'name':'Annie Cafe'}
item4 = {'category':'hotel::business', 'name':'Premier Inn'}
df = pd.DataFrame([item1, item2, item3, item4])
lookup_table = ['cafe', 'cafeteria', 'restaurant']
我想在DF中创建一个新列(是/否),该列与lookup_table匹配category列。类别列需要按“::”拆分以获取单个类别,并将其与列表中的不同值进行比较。在上面的示例中,除item4之外的所有内容都应为True。
我不想遍历df.category列中的每个项目,并检查它是否存在于表中。我对python来说相对较新....所以不仅仅是解决方案,我热衷于解决这个“python”方式的思维过程。
感谢
答案 0 :(得分:1)
选项1
str.contains
m = df.category.str.contains('|'.join(lookup_table))
df['Yes/No'] = np.where(m, 'Yes', 'No')
df
category name Yes/No
0 food::cafe::restaurant::business Bob Cafe Yes
1 food::take away::restaurant::business John Take Away Yes
2 cafeteria::business Annie Cafe Yes
3 hotel::business Premier Inn No
只需将lookup_table
中每个字符串的管道形成的“正则表达式”传递给str.contains
。然后返回一个掩码(根据行中是否匹配任何类别)。此掩码使用Yes
转换为No
/ np.where
个答案。
选项2
str.split
+ isin
+ any
m = df.category.str.split('::', expand=True).isin(lookup_table).any(1)
df['Yes/No'] = np.where(m, 'Yes', 'No')
df
category name Yes/No
0 food::cafe::restaurant::business Bob Cafe Yes
1 food::take away::restaurant::business John Take Away Yes
2 cafeteria::business Annie Cafe Yes
3 hotel::business Premier Inn No
与上面的选项类似,但这是纯字符串匹配,而不是正则表达式匹配。利用您的数据拆分::
(双冒号),这会导致数据框看起来像这样 -
i = df.category.str.split('::', expand=True)
i
0 1 2 3
0 food cafe restaurant business
1 food take away restaurant business
2 cafeteria business None None
3 hotel business None None
现在,请致电df.isin
,执行“等于?”检查lookup_table
中的每个字符串。这导致 -
j = i.isin(lookup_table)
0 1 2 3
0 False True True False
1 False False True False
2 True False False False
3 False False False False
下一步是在任意列中找到哪些行具有此类别...所以...使用any
。
j.any(axis=1)
0 True
1 True
2 True
3 False
dtype: bool
和以前一样,此掩码使用Yes
转换为No
/ np.where
个答案,但还有其他方法(例如replace
/ {{1 }})。
<强>计时强>
str.replace
df = pd.concat([df] * 100000, ignore_index=True)
%%timeit
m = df.category.str.contains('|'.join(lookup_table))
np.where(m, 'Yes', 'No')
1 loop, best of 3: 536 ms per loop
结果可能会因您的数据以及%%timeit
m = df.category.str.split('::', expand=True).isin(lookup_table).any(1)
df['Yes/No'] = np.where(m, 'Yes', 'No')
1 loop, best of 3: 2.31 s per loop
中的项目数量而异。