python pandas 将数据帧乘以向量化方式随类别变化的权重
python pandas multiply dataframe by weights that vary with category in vectorized fashion
我的问题与outlined here
非常相似
除了我的主数据框有一个类别列,我的权重也是如此:
df
Out[3]:
Symbol var_1 var_2 var_3 var_4 Category
Index
1903 0.000443 0.006928 0.000000 0.012375 A
1904 -0.000690 -0.007873 0.000171 0.014824 A
1905 -0.001354 0.001545 0.000007 -0.008195 C
1906 -0.001578 0.008796 -0.000164 0.015955 D
1907 -0.001578 0.008796 -0.000164 0.015955 A
1909 -0.001354 0.001545 0.000007 -0.008195 B
wgt_df
Out[4]:
Category var_1_wgt var_2_wgt var_3_wgt var_4_wgt
0 A 0.182022 0.182022 0.131243 0.182022
1 B 0.534814 0.534814 0.534814 0.534814
2 C 0.131243 0.534814 0.131243 0.182022
3 D 0.182022 0.151921 0.151921 0.131243
我想做的是为每个类别应用正确的权重以创建一个新列 df['new_var'],这是加权和。在没有类别的情况下,我可以将权重转换为 numpy 数组并使用看起来非常快的 .dot()
方法。但是,我看不出如何解决我的问题:如果我在主数据框 df 上使用 groupby()
,我肯定必须以某种方式对我的权重数据框 wgt_df 执行相同的操作。
实际上df有几百万行,我需要多次重复这个计算,所以我渴望找到一个向量化的解决方案;否则我可以做 df.groupby('Category')
,创建一个数据框的字典,其键是类别,例如wgts_dict['A'] = wgts_df[wgts_df.Category == 'A']
,并通过 lambda x
应用我的点逻辑,尽管我也不确定如何执行此操作,因为我需要明确引用当前正在处理的组元素以便拉出wgts_df
.
的正确切片
设置
print(df)
Out[655]:
var_1 var_2 var_3 var_4 Category
Symbol
1903 0.000443 0.006928 0.000000 0.012375 A
1904 -0.000690 -0.007873 0.000171 0.014824 A
1905 -0.001354 0.001545 0.000007 -0.008195 C
1906 -0.001578 0.008796 -0.000164 0.015955 D
1907 -0.001578 0.008796 -0.000164 0.015955 A
1909 -0.001354 0.001545 0.000007 -0.008195 B
print(w)
Out[656]:
Category var_1_wgt var_2_wgt var_3_wgt var_4_wgt
0 A 0.182022 0.182022 0.131243 0.182022
1 B 0.534814 0.534814 0.534814 0.534814
2 C 0.131243 0.534814 0.131243 0.182022
3 D 0.182022 0.151921 0.151921 0.131243
解决方案
#convert Category to numerical encoding
df['C_Number'] = df.Category.apply(lambda x: ord(x.lower())-97)
#Get a dot product for each row with all category weights and the extract the weights by the category number
df['new_var'] = ((df.iloc[:,:4].values).dot(w.iloc[:,-4:].values))[np.arange(len(df)),df.C_Number]
Out[654]:
var_1 var_2 var_3 var_4 Category C_Number new_var
Symbol
1903 0.000443 0.006928 0.000000 0.012375 A 0 0.006038
1904 -0.000690 -0.007873 0.000171 0.014824 A 0 -0.001615
1905 -0.001354 0.001545 0.000007 -0.008195 C 2 -0.000595
1906 -0.001578 0.008796 -0.000164 0.015955 D 3 0.006481
1907 -0.001578 0.008796 -0.000164 0.015955 A 0 0.007300
1909 -0.001354 0.001545 0.000007 -0.008195 B 1 -0.000661
您可以按类别进行分组(select,然后按类别进行 dot()
,或者您可以按类别进行 dot()
,然后 select。后者在 pandas 中更快更简单。请注意,我使用的数据与数据中的列名称和权重框架匹配。
代码 dot()
然后 select:
df['dot'] = df[df_wgt.columns].dot(df_wgt.T).lookup(df.index, df.Category)
执行的步骤...
Select 与 df[df_wgt.columns]
一起使用的列
这使用列标签和权重数据框中的排序。这很重要,因为 dot()
需要数据的顺序正确。
使用 .dot(df_wgt.T)
对转置权重数据帧执行点积
调换重量使它们处于 .dot()
的正确方向。这会计算每行数据的所有权重类别。这意味着在这种情况下,我们执行的乘法是所需次数的四倍,但它仍然可能比分组更快。
Select 与 .lookup(df.index, df.Category)
所需的点积
通过使用 lookup()
我们可以为该行的类别收集正确的结果。
代码 select (groupby) 然后 dot()
:
def dot(group):
category = group['Category'].iloc[0]
weights = df_wgt.loc[category].values
return pd.Series(
np.dot(group[df_wgt.columns].values, weights), index=group.index)
df['dot'] = df.groupby(['Category']).apply(dot) \
.reset_index().set_index('Index')[0]
测试代码:
import pandas as pd
from io import StringIO
df = pd.read_fwf(StringIO(u"""
Index var_1 var_2 var_3 var_4 Category
1903 0.000443 0.006928 0.000000 0.012375 A
1904 -0.000690 -0.007873 0.000171 0.014824 A
1905 -0.001354 0.001545 0.000007 -0.008195 C
1906 -0.001578 0.008796 -0.000164 0.015955 D
1907 -0.001578 0.008796 -0.000164 0.015955 A
1909 -0.001354 0.001545 0.000007 -0.008195 B"""),
header=1, skiprows=0).set_index(['Index'])
df_wgt = pd.read_fwf(StringIO(u"""
Category var_1 var_2 var_3 var_4
A 0.182022 0.182022 0.131243 0.182022
B 0.534814 0.534814 0.534814 0.534814
C 0.131243 0.534814 0.131243 0.182022
D 0.182022 0.151921 0.151921 0.131243"""),
header=1, skiprows=0).set_index(['Category'])
df['dot'] = df[df_wgt.columns].dot(df_wgt.T).lookup(df.index, df.Category)
print(df)
结果:
var_1 var_2 var_3 var_4 Category dot
Index
1903 0.000443 0.006928 0.000000 0.012375 A 0.003594
1904 -0.000690 -0.007873 0.000171 0.014824 A 0.001162
1905 -0.001354 0.001545 0.000007 -0.008195 C -0.000842
1906 -0.001578 0.008796 -0.000164 0.015955 D 0.003118
1907 -0.001578 0.008796 -0.000164 0.015955 A 0.004196
1909 -0.001354 0.001545 0.000007 -0.008195 B -0.004277
我的问题与outlined here
非常相似除了我的主数据框有一个类别列,我的权重也是如此:
df
Out[3]:
Symbol var_1 var_2 var_3 var_4 Category
Index
1903 0.000443 0.006928 0.000000 0.012375 A
1904 -0.000690 -0.007873 0.000171 0.014824 A
1905 -0.001354 0.001545 0.000007 -0.008195 C
1906 -0.001578 0.008796 -0.000164 0.015955 D
1907 -0.001578 0.008796 -0.000164 0.015955 A
1909 -0.001354 0.001545 0.000007 -0.008195 B
wgt_df
Out[4]:
Category var_1_wgt var_2_wgt var_3_wgt var_4_wgt
0 A 0.182022 0.182022 0.131243 0.182022
1 B 0.534814 0.534814 0.534814 0.534814
2 C 0.131243 0.534814 0.131243 0.182022
3 D 0.182022 0.151921 0.151921 0.131243
我想做的是为每个类别应用正确的权重以创建一个新列 df['new_var'],这是加权和。在没有类别的情况下,我可以将权重转换为 numpy 数组并使用看起来非常快的 .dot()
方法。但是,我看不出如何解决我的问题:如果我在主数据框 df 上使用 groupby()
,我肯定必须以某种方式对我的权重数据框 wgt_df 执行相同的操作。
实际上df有几百万行,我需要多次重复这个计算,所以我渴望找到一个向量化的解决方案;否则我可以做 df.groupby('Category')
,创建一个数据框的字典,其键是类别,例如wgts_dict['A'] = wgts_df[wgts_df.Category == 'A']
,并通过 lambda x
应用我的点逻辑,尽管我也不确定如何执行此操作,因为我需要明确引用当前正在处理的组元素以便拉出wgts_df
.
设置
print(df)
Out[655]:
var_1 var_2 var_3 var_4 Category
Symbol
1903 0.000443 0.006928 0.000000 0.012375 A
1904 -0.000690 -0.007873 0.000171 0.014824 A
1905 -0.001354 0.001545 0.000007 -0.008195 C
1906 -0.001578 0.008796 -0.000164 0.015955 D
1907 -0.001578 0.008796 -0.000164 0.015955 A
1909 -0.001354 0.001545 0.000007 -0.008195 B
print(w)
Out[656]:
Category var_1_wgt var_2_wgt var_3_wgt var_4_wgt
0 A 0.182022 0.182022 0.131243 0.182022
1 B 0.534814 0.534814 0.534814 0.534814
2 C 0.131243 0.534814 0.131243 0.182022
3 D 0.182022 0.151921 0.151921 0.131243
解决方案
#convert Category to numerical encoding
df['C_Number'] = df.Category.apply(lambda x: ord(x.lower())-97)
#Get a dot product for each row with all category weights and the extract the weights by the category number
df['new_var'] = ((df.iloc[:,:4].values).dot(w.iloc[:,-4:].values))[np.arange(len(df)),df.C_Number]
Out[654]:
var_1 var_2 var_3 var_4 Category C_Number new_var
Symbol
1903 0.000443 0.006928 0.000000 0.012375 A 0 0.006038
1904 -0.000690 -0.007873 0.000171 0.014824 A 0 -0.001615
1905 -0.001354 0.001545 0.000007 -0.008195 C 2 -0.000595
1906 -0.001578 0.008796 -0.000164 0.015955 D 3 0.006481
1907 -0.001578 0.008796 -0.000164 0.015955 A 0 0.007300
1909 -0.001354 0.001545 0.000007 -0.008195 B 1 -0.000661
您可以按类别进行分组(select,然后按类别进行 dot()
,或者您可以按类别进行 dot()
,然后 select。后者在 pandas 中更快更简单。请注意,我使用的数据与数据中的列名称和权重框架匹配。
代码 dot()
然后 select:
df['dot'] = df[df_wgt.columns].dot(df_wgt.T).lookup(df.index, df.Category)
执行的步骤...
Select 与
一起使用的列df[df_wgt.columns]
这使用列标签和权重数据框中的排序。这很重要,因为
dot()
需要数据的顺序正确。使用
对转置权重数据帧执行点积.dot(df_wgt.T)
调换重量使它们处于
.dot()
的正确方向。这会计算每行数据的所有权重类别。这意味着在这种情况下,我们执行的乘法是所需次数的四倍,但它仍然可能比分组更快。Select 与
所需的点积.lookup(df.index, df.Category)
通过使用
lookup()
我们可以为该行的类别收集正确的结果。
代码 select (groupby) 然后 dot()
:
def dot(group):
category = group['Category'].iloc[0]
weights = df_wgt.loc[category].values
return pd.Series(
np.dot(group[df_wgt.columns].values, weights), index=group.index)
df['dot'] = df.groupby(['Category']).apply(dot) \
.reset_index().set_index('Index')[0]
测试代码:
import pandas as pd
from io import StringIO
df = pd.read_fwf(StringIO(u"""
Index var_1 var_2 var_3 var_4 Category
1903 0.000443 0.006928 0.000000 0.012375 A
1904 -0.000690 -0.007873 0.000171 0.014824 A
1905 -0.001354 0.001545 0.000007 -0.008195 C
1906 -0.001578 0.008796 -0.000164 0.015955 D
1907 -0.001578 0.008796 -0.000164 0.015955 A
1909 -0.001354 0.001545 0.000007 -0.008195 B"""),
header=1, skiprows=0).set_index(['Index'])
df_wgt = pd.read_fwf(StringIO(u"""
Category var_1 var_2 var_3 var_4
A 0.182022 0.182022 0.131243 0.182022
B 0.534814 0.534814 0.534814 0.534814
C 0.131243 0.534814 0.131243 0.182022
D 0.182022 0.151921 0.151921 0.131243"""),
header=1, skiprows=0).set_index(['Category'])
df['dot'] = df[df_wgt.columns].dot(df_wgt.T).lookup(df.index, df.Category)
print(df)
结果:
var_1 var_2 var_3 var_4 Category dot
Index
1903 0.000443 0.006928 0.000000 0.012375 A 0.003594
1904 -0.000690 -0.007873 0.000171 0.014824 A 0.001162
1905 -0.001354 0.001545 0.000007 -0.008195 C -0.000842
1906 -0.001578 0.008796 -0.000164 0.015955 D 0.003118
1907 -0.001578 0.008796 -0.000164 0.015955 A 0.004196
1909 -0.001354 0.001545 0.000007 -0.008195 B -0.004277