如何对两个Pandas DataFrame的行执行外积运算?
Pandas 实现两个DataFrame全行列对应乘积并保留标签
问题描述
有两个列标签完全一致的Pandas DataFrame,列包含label、data1、data2……dataN。需要对两个DataFrame的所有行组合进行对应数据列的乘积运算(即data1与data1相乘、data2与data2相乘等),并在结果DataFrame中保留两个原DataFrame的label列。
示例数据
Frame 1
| label | d1 | d2 | d3 |
|---|---|---|---|
| a | 1 | 2 | 3 |
| b | 4 | 5 | 6 |
Frame 2
| label | d1 | d2 | d3 |
|---|---|---|---|
| c | 7 | 8 | 9 |
| d | 10 | 11 | 12 |
期望结果
| label_1 | label_2 | d1 | d2 | d3 |
|---|---|---|---|---|
| a | c | 7 | 16 | 27 |
| a | d | 10 | 22 | 36 |
| b | c | 28 | 40 | 54 |
| b | d | 40 | 55 | 72 |
最优实现方案
不需要用低效的循环,利用Pandas的笛卡尔积合并结合广播乘法就能高效完成,以下是两种可行方案:
方案一:基于Pandas合并的常规写法
import pandas as pd # 构造示例数据 df1 = pd.DataFrame({'label': ['a', 'b'], 'd1': [1,4], 'd2': [2,5], 'd3': [3,6]}) df2 = pd.DataFrame({'label': ['c', 'd'], 'd1': [7,10], 'd2': [8,11], 'd3': [9,12]}) # 重命名label列,避免合并冲突 df1 = df1.rename(columns={'label': 'label_1'}) df2 = df2.rename(columns={'label': 'label_2'}) # 添加临时键生成笛卡尔积 df1['key'] = 1 df2['key'] = 1 cartesian_df = pd.merge(df1, df2, on='key').drop('key', axis=1) # 获取数据列名 data_cols = [col for col in df1.columns if col not in ['label_1', 'key']] # 对应列相乘 cartesian_df[data_cols] = cartesian_df[[f'{col}_x' for col in data_cols]] * cartesian_df[[f'{col}_y' for col in data_cols]] # 清理多余列 cartesian_df = cartesian_df.drop([col for col in cartesian_df.columns if '_x' in col or '_y' in col], axis=1) print(cartesian_df)
方案二:基于Numpy广播的高效写法(内存更友好)
适合数据量较大的场景,直接用Numpy广播完成乘积运算,减少中间列的生成:
import pandas as pd import numpy as np # 构造示例数据 df1 = pd.DataFrame({'label': ['a', 'b'], 'd1': [1,4], 'd2': [2,5], 'd3': [3,6]}) df2 = pd.DataFrame({'label': ['c', 'd'], 'd1': [7,10], 'd2': [8,11], 'd3': [9,12]}) # 重命名label列 df1 = df1.rename(columns={'label': 'label_1'}) df2 = df2.rename(columns={'label': 'label_2'}) # 提取数据部分并做广播乘积 df1_data = df1.drop('label_1', axis=1).to_numpy()[:, None, :] df2_data = df2.drop('label_2', axis=1).to_numpy()[None, :, :] product_data = (df1_data * df2_data).reshape(-1, df1_data.shape[-1]) # 生成标签的笛卡尔积 labels = pd.merge(df1[['label_1']].assign(key=1), df2[['label_2']].assign(key=1), on='key').drop('key', axis=1) # 合并标签与乘积结果 result_df = pd.concat([labels, pd.DataFrame(product_data, columns=df1.drop('label_1', axis=1).columns)], axis=1) print(result_df)
两种方案都能得到符合要求的结果,其中方案二的内存开销更小,运算效率更高。
内容的提问来源于stack exchange,提问作者Immot
相关产品推荐
相关产品推荐

