pandas dataframe 按权重在一行中拆分值
pandas dataframe split values in one row by weights
这似乎是一个基本问题,但我想出了一个优雅的解决方案。
我有一个 pandas 数据框,其中所有值都已分配到一行中。但是,我需要按权重将值拆分为多行。此处示例:
输入数据帧:
import pandas as pd
# starting df with weights W.
df_input = pd.DataFrame({
'W': [0.3, 0.2, 0.5],
'X1': [100, 0, 0],
'X2': [150, 0, 0],
'X3': [200, 0, 0],
'X4': [300, 0, 0]
})
所需的输出数据帧:
df_output = pd.DataFrame({
'W': [0.3, 0.2, 0.5],
'X1': [30, 20, 50],
'X2': [45, 30, 75],
'X3': [60, 40, 100],
'X4': [90, 60, 150]
})
屏幕截图:
如果我没理解错的话,这只是一个简单的矩阵乘法。
从 (3,1) 矩阵开始,乘以 (1,3)。
最终结果将是 (3,3)。如果这种解决方法有任何帮助,请告诉我:
import numpy as np
A = np.array([[3,6,7],[5,-3,0]])
B = np.array([[1,1],[2,1],[3,-1]])
C = A.dot(B)
print (C)
Output:
[[36,-12],
[-1, 2]
优雅是主观的 - 一种可能的方法是使用 pd.clip
for col in ['X1', 'X2', 'X3', 'X4']:
df_input[col] = df_input[col].clip(lower=df_input[col].max())
df_input[col]*=df_input['W']
结果如上
纯pandas解决方案:
df_output = df_input.copy()
df_output.loc[:, 'X1':] = df_output.loc[:, 'X1':].apply(lambda col: col[0] * df_output['W'])
或者使用 numpy 广播:
df_output = df_input.copy()
df_output.loc[:, 'X1':] = df_output.loc[0, 'X1':].values[None, :] * df_output['W'].values[:, None]
使用 DataFrame.ffill
填充列中的值,然后将它们乘以 DataFrame.multiply
的因数
values = df_input.replace(0, np.NaN).ffill()
df_input.iloc[:, 1:] = values.iloc[:, 1:].mul(df_input['W'], axis=0)
或者我们可以使用 numpy
,但首先我们必须将数组重塑为 (,1)
values = df_input.replace(0, np.NaN).ffill()
df_input.iloc[:, 1:] = values.iloc[:, 1:] * values['W'].to_numpy()[:, None]
W X1 X2 X3 X4
0 0.3 30.0 45.0 60.0 90.0
1 0.2 20.0 30.0 40.0 60.0
2 0.5 50.0 75.0 100.0 150.0
将数据输出到numpy
数组,然后计算点积
- 从行和列数据创建两个数组
- 塑造阵列
np.dot
两个数组
import pandas as pd
import numpy as np
# using your data
# weight
w = df_input.iloc[:, 0].to_numpy().reshape(len(df_input), 1)
array([[0.3],
[0.2],
[0.5]])
# values
v = df_input.iloc[0, 1:].to_numpy().reshape(1, len(df_input.columns[1:]))
array([[30., 45., 60., 90.]])
# load dot product into a dataframe
df_out = pd.DataFrame(np.dot(w, v))
# add column names
df_out.columns = df_input.columns[1:]
# insert W if needed
df_out.insert(0, 'W', df_input['W'])
# output
W X1 X2 X3 X4
0.3 30.0 45.0 60.0 90.0
0.2 20.0 30.0 40.0 60.0
0.5 50.0 75.0 100.0 150.0
这里是已经提供的优秀答案的替代方案:
仅获取 x 列:
x_columns = df_input.filter(like='X').columns
计算(评论中嵌入的解释):
df_input.loc[:,x_columns] = (df_input.loc[:,x_columns]
#spill the non zero values downwards
.replace(0,method='ffill')
#multiply by the 'W' column
.mul(df_input['W'],axis=0)
.astype(int)
)
W X1 X2 X3 X4
0 0.3 30 45 60 90
1 0.2 20 30 40 60
2 0.5 50 75 100 150
这似乎是一个基本问题,但我想出了一个优雅的解决方案。
我有一个 pandas 数据框,其中所有值都已分配到一行中。但是,我需要按权重将值拆分为多行。此处示例:
输入数据帧:
import pandas as pd
# starting df with weights W.
df_input = pd.DataFrame({
'W': [0.3, 0.2, 0.5],
'X1': [100, 0, 0],
'X2': [150, 0, 0],
'X3': [200, 0, 0],
'X4': [300, 0, 0]
})
所需的输出数据帧:
df_output = pd.DataFrame({
'W': [0.3, 0.2, 0.5],
'X1': [30, 20, 50],
'X2': [45, 30, 75],
'X3': [60, 40, 100],
'X4': [90, 60, 150]
})
屏幕截图:
如果我没理解错的话,这只是一个简单的矩阵乘法。 从 (3,1) 矩阵开始,乘以 (1,3)。 最终结果将是 (3,3)。如果这种解决方法有任何帮助,请告诉我:
import numpy as np
A = np.array([[3,6,7],[5,-3,0]])
B = np.array([[1,1],[2,1],[3,-1]])
C = A.dot(B)
print (C)
Output:
[[36,-12],
[-1, 2]
优雅是主观的 - 一种可能的方法是使用 pd.clip
for col in ['X1', 'X2', 'X3', 'X4']:
df_input[col] = df_input[col].clip(lower=df_input[col].max())
df_input[col]*=df_input['W']
结果如上
纯pandas解决方案:
df_output = df_input.copy()
df_output.loc[:, 'X1':] = df_output.loc[:, 'X1':].apply(lambda col: col[0] * df_output['W'])
或者使用 numpy 广播:
df_output = df_input.copy()
df_output.loc[:, 'X1':] = df_output.loc[0, 'X1':].values[None, :] * df_output['W'].values[:, None]
使用 DataFrame.ffill
填充列中的值,然后将它们乘以 DataFrame.multiply
values = df_input.replace(0, np.NaN).ffill()
df_input.iloc[:, 1:] = values.iloc[:, 1:].mul(df_input['W'], axis=0)
或者我们可以使用 numpy
,但首先我们必须将数组重塑为 (,1)
values = df_input.replace(0, np.NaN).ffill()
df_input.iloc[:, 1:] = values.iloc[:, 1:] * values['W'].to_numpy()[:, None]
W X1 X2 X3 X4
0 0.3 30.0 45.0 60.0 90.0
1 0.2 20.0 30.0 40.0 60.0
2 0.5 50.0 75.0 100.0 150.0
将数据输出到numpy
数组,然后计算点积
- 从行和列数据创建两个数组
- 塑造阵列
np.dot
两个数组
import pandas as pd
import numpy as np
# using your data
# weight
w = df_input.iloc[:, 0].to_numpy().reshape(len(df_input), 1)
array([[0.3],
[0.2],
[0.5]])
# values
v = df_input.iloc[0, 1:].to_numpy().reshape(1, len(df_input.columns[1:]))
array([[30., 45., 60., 90.]])
# load dot product into a dataframe
df_out = pd.DataFrame(np.dot(w, v))
# add column names
df_out.columns = df_input.columns[1:]
# insert W if needed
df_out.insert(0, 'W', df_input['W'])
# output
W X1 X2 X3 X4
0.3 30.0 45.0 60.0 90.0
0.2 20.0 30.0 40.0 60.0
0.5 50.0 75.0 100.0 150.0
这里是已经提供的优秀答案的替代方案:
仅获取 x 列:
x_columns = df_input.filter(like='X').columns
计算(评论中嵌入的解释):
df_input.loc[:,x_columns] = (df_input.loc[:,x_columns]
#spill the non zero values downwards
.replace(0,method='ffill')
#multiply by the 'W' column
.mul(df_input['W'],axis=0)
.astype(int)
)
W X1 X2 X3 X4
0 0.3 30 45 60 90
1 0.2 20 30 40 60
2 0.5 50 75 100 150