Pandas将列与另一个列表进行比较

时间:2017-12-28 18:45:59

标签: python pandas

我有一个看起来像这样的数据框

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”方式的思维过程。

感谢

1 个答案:

答案 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 中的项目数量而异。