Python 熊猫数据帧中基于词包的匹配

Python 熊猫数据帧中基于词包的匹配,python,pandas,function,multi-index,Python,Pandas,Function,Multi Index,我有几个映射规则,下面是规则 Type A: Chicken, Beef, Goat Type B: Fish, Shrimp Type C: Chicken, Pork 我想补充一下 id Menu 1 Fried Chicken 2 Shrimp Chips 3 Pork with Cheese 4 Fish Spaghetti 5 Goat Sate 6 Beef Soup 我想做这样的标签 id

我有几个映射规则,下面是规则

Type A: Chicken, Beef, Goat
Type B: Fish, Shrimp
Type C: Chicken, Pork
我想补充一下

 id   Menu
   1    Fried Chicken
   2    Shrimp Chips
   3    Pork with Cheese
   4    Fish Spaghetti
   5    Goat Sate
   6    Beef Soup
我想做这样的标签

 id     Menu                 Type A   Type B   Type C
   1    Fried Chicken        1        0        1
   2    Shrimp Chips         0        1        0
   3    Pork with Cheese     0        0        1
   4    Fish Spaghetti       0        1        0
   5    Goat Sate            1        0        0
   6    Beef Soup            1        0        0

我将映射规则转换为一个
pd.MultiIndex

from numpy.core.defchararray import find

m = {
    'Type A': ['Chicken', 'Beef', 'Goat'],
    'Type B': ['Fish', 'Shrimp'],
    'Type C': ['Chicken', 'Pork']
}

mux = pd.MultiIndex.from_tuples(
    [(k, v) for k, values in m.items() for v in values])

选项0
使用
pd.Series.str.get\u假人的最简单方法

df.join(
    df.Menu.str.get_dummies(sep=' ') \
      .reindex(columns=mux, level=1).max(axis=1, level=0)
)

   id              Menu  Type A  Type B  Type C
0   1     Fried Chicken       1       0       1
1   2      Shrimp Chips       0       1       0
2   3  Pork with Cheese       0       0       1
3   4    Fish Spaghetti       0       1       0
4   5         Goat Sate       1       0       0
5   6         Beef Soup       1       0       0

选项1
使用
numpy.core.defchararray.find

menu = df.Menu.values.astype(str)

d1 = pd.DataFrame(
    (find(menu[:, None], mux.levels[1]) >= 0).astype(int),
    columns = mux.levels[1]
)

df.join(d1.reindex(columns=mux, level=1).max(axis=1, level=0))

   id              Menu  Type A  Type B  Type C
0   1     Fried Chicken       1       0       1
1   2      Shrimp Chips       0       1       0
2   3  Pork with Cheese       0       0       1
3   4    Fish Spaghetti       0       1       0
4   5         Goat Sate       1       0       0
5   6         Beef Soup       1       0       0

选项2
使用
pd.Series.str.extractall

d1 = pd.get_dummies(
    df.Menu.str.extractall(
        '({})'.format('|'.join(mux.levels[1]))
    )[0]
).sum(level=0)

df.join(d1.reindex(columns=mux, level=1).max(axis=1, level=0))

   id              Menu  Type A  Type B  Type C
0   1     Fried Chicken       1       0       1
1   2      Shrimp Chips       0       1       0
2   3  Pork with Cheese       0       0       1
3   4    Fish Spaghetti       0       1       0
4   5         Goat Sate       1       0       0
5   6         Beef Soup       1       0       0

选项1的解释
使用
pd.MultiIndex
将使我能够使用
np.core.defchararray.find
仅查找我要查找的所有单词的唯一值,并能够将它们映射回可能的多个键

mux = pd.MultiIndex.from_tuples(
    [(k, v) for k, values in m.items() for v in values])
mux
将如下所示:

 Type A           Type B         Type C     
Chicken Beef Goat   Fish Shrimp Chicken Pork
但是,
mux
的唯一值在
mux.levels[1]
中。我使用它来使用find查找我的值

d1 = pd.DataFrame(
    (find(menu[:, None], mux.levels[1]) >= 0).astype(int),
    columns = mux.levels[1]
)

d1

   Beef  Chicken  Fish  Goat  Pork  Shrimp
0     0        1     0     0     0       0
1     0        0     0     0     0       1
2     0        0     0     0     1       0
3     0        0     1     0     0       0
4     0        0     0     1     0       0
5     1        0     0     0     0       0
现在我可以
pd.DataFrame.reindex
columns
level=1

d1.reindex(columns=mux, level=1)

   Type A           Type B         Type C     
  Chicken Beef Goat   Fish Shrimp Chicken Pork
0       1    0    0      0      0       1    0
1       0    0    0      0      1       0    0
2       0    0    0      0      0       0    1
3       0    0    0      1      0       0    0
4       0    0    1      0      0       0    0
5       0    1    0      0      0       0    0
我把
轴=1
级别=0
连接
上的
最大值
拿回来。。。这就是我上面展示的


定时


下面的代码是一个简单的解决方案

将熊猫作为pd导入
从io导入StringIO
m={
‘A型’:[‘鸡肉’、‘牛肉’、‘山羊’],
‘B类’:[‘鱼’、‘虾’],
‘C型’:[‘鸡肉’、‘猪肉’]
}
csv=StringIO(““”id,菜单
1、炸鸡
2、虾片
3、奶酪猪肉
4、鱼意大利面
5、山羊状态
(六、牛肉汤)
df=pd.read\U csv(csv)
对于m中的键:
df[key]=df[“Menu”].str.contains(“|”).join(m[key]).astype(int)
df
#出[3]:
#id菜单类型A类型B类型C
#0 1炸鸡1 0 1
#12片虾片0110
#2 3奶酪猪肉0 1
#3 4鱼意大利面01 0
#4 5山羊状态1 0 0
#5 6牛肉汤100

您可以添加计时吗?谢谢您的计时,我注意到您现在添加了计时。我认为我的答案很酷。这更简单、更快。不过,我会将其更改为
df.assign(**{k:df.Menu.str.contains('.|'.join(m[k])).astype(int)for k in m})
感谢您的补充和时间测量。你的答案也已经被研究过了。有一件事我还没有测试过,那就是当字典有更多的键时会发生什么。我以后再玩。无论如何,回答得好!
def pir0(df, m):
    mux = pd.MultiIndex.from_tuples(
        [(k, v) for k, values in m.items() for v in values])

    return df.join(
        df.Menu.str.get_dummies(sep=' ') \
          .reindex(columns=mux, level=1).max(axis=1, level=0)
    )

def pir1(df, m):
    mux = pd.MultiIndex.from_tuples(
        [(k, v) for k, values in m.items() for v in values])

    menu = df.Menu.values.astype(str)

    d1 = pd.DataFrame(
        (find(menu[:, None], mux.levels[1]) >= 0).astype(int),
        columns = mux.levels[1]
    )

    return df.join(d1.reindex(columns=mux, level=1).max(axis=1, level=0))

def pir2(df, m):
    mux = pd.MultiIndex.from_tuples(
        [(k, v) for k, values in m.items() for v in values])

    d1 = pd.get_dummies(
        df.Menu.str.extractall(
            '({})'.format('|'.join(mux.levels[1]))
        )[0]
    ).sum(level=0)

    return df.join(d1.reindex(columns=mux, level=1).max(axis=1, level=0))


def keiku(df, m):
    return df.assign(**{k: df.Menu.str.contains('|'.join(m[k])).astype(int) for k in m})


res = pd.DataFrame(
    index=[10, 30, 100, 300, 1000],
    columns='pir0 pir1 pir2 keiku'.split(),
    dtype=float
)

for i in res.index:
    d = pd.concat([df] * i, ignore_index=True)
    for j in res.columns:
        stmt = '{}(d, m)'.format(j)
        setp = 'from __main__ import d, m, {}'.format(j)
        res.at[i, j] = timeit(stmt, setp, number=20)

res.plot(loglog=True)