如何对以下内容进行矢量化,追加可能是瓶颈

How to vectorize the following, the append is probably the bottleneck

我有以下包含两列 c1c2 的数据框,我想根据以下逻辑添加一个新列 c3,我的工作有效但速度很慢, 任何人都可以建议一种对此进行矢量化的方法吗?

代码

import pandas as pd

df = pd.DataFrame(
    {
        "c1": [1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2],
        "c2": ["a", "a", "a", "b", "b", "b", "y", "y", "y", "z", "z", "z"],
    }
)
new_df = pd.DataFrame()
values = {1: ["a1", "a2"], 2: ["b1", "b2"]}
for i, j in df.groupby("c1"):
    for idx, (k, l) in enumerate(j.groupby("c2")):
        l["c3"] = values[i][idx]
        new_df = new_df.append(l)

输出(有效但我的代码很慢)

    c1 c2  c3
0    1  a  a1
1    1  a  a1
2    1  a  a1
3    1  b  a2
4    1  b  a2
5    1  b  a2
6    2  y  b1
7    2  y  b1
8    2  y  b1
9    2  z  b2
10   2  z  b2
11   2  z  b2
In [203]: a = pd.DataFrame([[k, value, idx] for k,v in values.items() for idx,value in enumerate(v)], columns=['c1', 'c3', 'gr'])
     ...: b = df.assign(gr=df.groupby(['c1']).transform(lambda x: (x.ne(x.shift()).cumsum())- 1))
     ...: print(b)
     ...: b.merge(a).drop(columns='gr')
     ...:
# b
    c1 c2  gr
0    1  a   0
1    1  a   0
2    1  a   0
3    1  b   1
4    1  b   1
5    1  b   1
6    2  y   0
7    2  y   0
8    2  y   0
9    2  z   1
10   2  z   1
11   2  z   1
Out[203]:
    c1 c2  c3
0    1  a  a1
1    1  a  a1
2    1  a  a1
3    1  b  a2
4    1  b  a2
5    1  b  a2
6    2  y  b1
7    2  y  b1
8    2  y  b1
9    2  z  b2
10   2  z  b2
11   2  z  b2

如果你不介意使用其他库,你基本上需要在你的组中标记编码:

from sklearn.preprocessing import LabelEncoder

def le(x):
    return pd.DataFrame(LabelEncoder().fit_transform(x),index=x.index)
    
df['idx'] = df.groupby('c1')['c2'].apply(le)

df['c3'] = df.apply(lambda x:values[x['c1']][x['idx']],axis=1)

    c1 c2  idx  c3
0    1  a    0  a1
1    1  a    0  a1
2    1  a    0  a1
3    1  b    1  a2
4    1  b    1  a2
5    1  b    1  a2
6    2  y    0  b1
7    2  y    0  b1
8    2  y    0  b1
9    2  z    1  b2
10   2  z    1  b2
11   2  z    1  b2

否则就是使用 pd.Categorical 的问题,与上面的概念相同,只是你在每个组内转换,将列转换为一个类别,然后提取代码:

def le(x):
    return pd.DataFrame(pd.Categorical(x).codes,index=x.index)