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)