如何用计数在熊猫中进行vlookup

时间:2018-08-07 12:24:33

标签: pandas merge count pivot vlookup

我有以下两个输入数据帧:

df_item_in_cat
      a     b     c     d
0     A     A     B     A
1     B     B     E     B
2     C     E     F     E
3     D     F     G     G

df_charac_by_cat
    cat      charac
0     a          10
1     b          20
2     c          25
3     d          15

我想生成以下数据框:

df
   item   cat_nb   sum_charac
0     A        3           45
1     B        4           70
2     C        1           10
3     D        1           10
4     E        2           45
5     F        2           45
6     G        2           40

其中:

  • cat_nb是df_item_in_cat中每个项目出现的列的nb
  • sum_charac是来自df_charac_by_cat的不同类别的charac的总和

如果需要,我可以得到意甲:

s_items

0  A
1  B
2  C
3  D
4  E
5  F
6  G

更具体地说,我有属于类别的产品,并且有与类别关联的商店。 我想根据每种产品的类别和每种商店的类别来了解每种产品在多少家商店中可用。希望很清楚..

  • (a,b,c,d)是类别
  • (A,B,C,D,E,F,G)是产品
  • (10,20,25,15)是与每个类别关联的商店数量

ex :3种类别(a,b,d)的产品A在45家商店中可用,因为10 + 20 + 15 = 45

这就像excel中的“ vlookup”。

我很确定我可以通过迭代来做到这一点,但是我正在寻找一种“美丽”的解决方案。

我想向您展示一些研究,但是我真的不知道该怎么做.. 我尝试了合并或透视,但这并不是真的有用。

3 个答案:

答案 0 :(得分:4)

您需要:

df_item_in_cat.melt().merge(df_charac_by_cat, left_on='variable', right_on='cat')\
   .groupby('value')['charac'].agg(['count','sum'])

输出:

  value  count  sum
0     A      3   45
1     B      4   70
2     C      1   10
3     D      1   10
4     E      3   60
5     F      2   45
6     G      2   40

而且,这是所有列重命名和“整理”的事情:

df_item_in_cat.melt(value_name='item').merge(df_charac_by_cat, left_on='variable', right_on='cat')\
              .groupby('item')['charac'].agg(['count','sum']).reset_index()\
              .rename(columns={'count':'cat_nb','sum':'sum_charac'})

输出:

  item  cat_nb  sum_charac
0    A       3          45
1    B       4          70
2    C       1          10
3    D       1          10
4    E       3          60
5    F       2          45
6    G       2          40

答案 1 :(得分:2)

ScottBoston的答案要好得多,但我仍然很喜欢我所做的事情。

我在想什么

  1. 将两个输入数据帧都转换为序列,以便我可以对新索引进行操作。
  2. 该索引应基于df_item_in_cat中的值
  3. 我将计算该索引
  4. 然后映射值和总和
  5. 做一些会计工作来获取列名应该是什么

siic = df_item_in_cat.pipe(
    lambda d: pd.Series(np.tile(d.columns, len(d)), d.values.ravel())
)

scbc = df_charac_by_cat.set_index(['cat']).charac

pd.concat(dict(
    cat_nb=siic.groupby(level=0).count(),
    sum_charac=siic.map(scbc).sum(level=0)
), axis=1, sort=True).rename_axis('item').reset_index()

  item  cat_nb  sum_charac
0    A       3          45
1    B       4          70
2    C       1          10
3    D       1          10
4    E       3          60
5    F       2          45
6    G       2          40

答案 2 :(得分:2)

知道我来晚了,但是我也很喜欢我的解决方案;)

使用np.unique

可轻松获得第一列
v, _, c = np.unique(df.values, 1, return_counts=True)

产生

>>> print(v,c)
['A' 'B' 'C' 'D' 'E' 'F' 'G'], [3 4 1 1 3 2 2]

然后

dff = pd.DataFrame(dict(zip(v,c)), index=['cat_nb']).T

   cat_nb
A       3
B       4
C       1
D       1
E       3
F       2
G       2

第二列比较棘手,但仍可以使用defaultdict进行管理

x = defaultdict(set)
from collections import defaultdict
for d in df.to_dict('r'):
    for k,v in d.items():
        x[v].add(k)

如此

>>> x
{'A': {'a', 'b', 'd'},
 'B': {'a', 'b', 'c', 'd'},
 'E': {'b', 'c', 'd'},
 'C': {'a'},
 'F': {'b', 'c'},
 'D': {'a'},
 'G': {'c', 'd'}}

然后我们可以使用O(1)查询字典来映射它

d2 = df2.set_index('cat').to_dict()['charac']
s = pd.Series({k: sum(d2[v_] for v_ in v) for k,v in (x).items()})

dff.loc[:, 'f'] = s

我们有输出

    cat_nb  f
A   3       45
B   4       70
C   1       10
D   1       10
E   3       60
F   2       45
G   2       40