如何用 pandas 构造向量化函数?

How to structure vectorized function with pandas?

我不确定如何构造一个我想在 pandas 中向量化的函数。

我有两个这样的 df:

contents = pd.DataFrame({
'Items': [1, 2, 3, 1, 1, 2],
})

cats = pd.DataFrame({
'Cat1': ['1|2|4'],
'Cat2': ['3|2|5'],
'Cat3': ['6|9|11'],
})

我的目标是 .insert contents 的新列,如果 contents['Items']cats['cat1'] 的元素,则每行是 10 否则。每 cat.

重复一次

目标格式:

contents = pd.DataFrame({
'Items': [1, 2, 3, 1, 1, 2],
'contains_Cat1': [1, 1, 0, 1, 1, 1],
'contains_Cat2': [0, 1, 1, 0, 0, 1],
'contains_Cat3': [0, 0, 0, 0, 0, 0],
})

由于我的内容 df 很大 (!) 我想对其进行矢量化。我对每只猫的做法是做这样的事情

contents.insert(
    loc=len(contents.columns),
    column='contains_Cat1',
    value=has_content(contents, cats['Cat1'])

def has_content(contents: pd.DataFrame, cat: pd.Series) -> pd.Series:
    # Initialization of pd.Series here??
    if contents['Items'] in cat:
        return True
    else:
        return False

我的问题是:如何构建我的 has_content(...)?我特别不清楚的是我如何初始化 pd.Series 以包含所有 False 值。我什至需要吗?之后,我知道如何检查其他内容是否包含某些内容。但是我真的可以像上面那样按列并 return 立即进行而不变成按单元格吗?

尝试使用 str.get_dummies,然后使用 stackunstack

重新整形
out = cats.stack().str.get_dummies().stack()\
          .unstack(level=1).reset_index(level=0,drop=True)\
           .reindex(contents.Items.astype(str))
Out[229]: 
       Cat1  Cat2  Cat3
Items                  
1         1     0     0
2         1     1     0
3         0     1     0
1         1     0     0
1         1     0     0
2         1     1     0

改进:

out=cats.stack().str.get_dummies().droplevel(0).T\
        .add_prefix('contains_').reindex(contents['Items'].astype(str)).reset_index()

Out[230]: 

    Items   contains_Cat1   contains_Cat2   contains_Cat3
0   1       1               0               0
1   2       1               1               0
2   3       0               1               0
3   1       1               0               0
4   1       1               0               0
5   2       1               1               0

简单方法:

contents = (contents.join([pd.Series(contents.Items.astype(str).
                                     str.contains(cats[c][0]).astype(int), 
                                     name="Contains_"+c) for c in cats]))

内容:

    Items   contains_Cat1   contains_Cat2   contains_Cat3
0   1       1               0               0
1   2       1               1               0
2   3       0               1               0
3   1       1               0               0
4   1       1               0               0
5   2       1               1               0

时间比较:

%%timeit -n 2000
(contents.join([pd.Series(contents.Items.astype(str).
                                     str.contains(cats[c][0]).astype(int), 
                                     name="Contains_"+c) for c in cats]))

3.01 ms ± 344 µs per loop (mean ± std. dev. of 7 runs, 2000 loops each)


%%timeit -n 2000
cats.stack().str.get_dummies().stack()\
          .unstack(level=1).reset_index(level=0,drop=True)\
           .reindex(contents.Items.astype(str))

5.13 ms ± 584 µs per loop (mean ± std. dev. of 7 runs, 2000 loops each)


%%timeit -n 2000
cats.stack().str.get_dummies().droplevel(0).T\
        .add_prefix('contains_').reindex(contents['Items'].astype(str)).reset_index()

4.58 ms ± 512 µs per loop (mean ± std. dev. of 7 runs, 2000 loops each)