如何对以下内容进行矢量化,追加可能是瓶颈
How to vectorize the following, the append is probably the bottleneck
我有以下包含两列 c1
和 c2
的数据框,我想根据以下逻辑添加一个新列 c3
,我的工作有效但速度很慢, 任何人都可以建议一种对此进行矢量化的方法吗?
- 必须根据
c1
和 c2
进行分组,然后对于每个组,新列 c3
必须从 values
开始按顺序填充,其中键是c1
的值和每个“子组”将有后续值,IOW values[value_of_c1][idx]
,其中 idx
是“子组”,示例如下
- 第一组
(1, 'a')
,这里c1
是1
,“子组”"a"
索引是0
(第一个子组1 ) 因此该组中所有行的 c3
是 values[1][0]
- 第二组
(1, 'b')
这里 c1
仍然是 1
但“子组”是 "b"
所以索引 1
(第二个子组 1 ) 因此对于该组中的所有行 c3
是 values[1][1]
- 这里
c1
的第三组(2, 'y')
现在是2
,“子组”是"a"
,索引是0
(第一个子组2), 所以对于这个组中的所有行 c3
是 values[2][0]
- 以此类推
values
将具有满足此逻辑的必要元素。
代码
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)
我有以下包含两列 c1
和 c2
的数据框,我想根据以下逻辑添加一个新列 c3
,我的工作有效但速度很慢, 任何人都可以建议一种对此进行矢量化的方法吗?
- 必须根据
c1
和c2
进行分组,然后对于每个组,新列c3
必须从values
开始按顺序填充,其中键是c1
的值和每个“子组”将有后续值,IOWvalues[value_of_c1][idx]
,其中idx
是“子组”,示例如下 - 第一组
(1, 'a')
,这里c1
是1
,“子组”"a"
索引是0
(第一个子组1 ) 因此该组中所有行的c3
是values[1][0]
- 第二组
(1, 'b')
这里c1
仍然是1
但“子组”是"b"
所以索引1
(第二个子组 1 ) 因此对于该组中的所有行c3
是values[1][1]
- 这里
c1
的第三组(2, 'y')
现在是2
,“子组”是"a"
,索引是0
(第一个子组2), 所以对于这个组中的所有行c3
是values[2][0]
- 以此类推
values
将具有满足此逻辑的必要元素。
代码
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)