在多级索引DataFrame中使用向量操作列并添加新列的优化方案咨询
在多级索引DataFrame中使用向量操作列并添加新列的优化方案咨询
你好,针对你提出的需求,完全可以用pandas的向量化操作替代循环,实现更简洁高效的处理,不需要手动创建空DataFrame再循环赋值。下面是具体的优化方案:
场景回顾
你有两个DataFrame:
df1:日期索引,列是二级多级索引,Level 0为Capitals(包含A、B、C),Level 1为Smalls(包含a、b、c、d、e),结构如下:
| Capitals | A | B | C | ||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Smalls | a | b | c | d | e | a | b | c | d | e | a | b | c | d | e |
| Date | |||||||||||||||
| 01-01-25 | |||||||||||||||
| 01-02-25 | |||||||||||||||
| 01-03-25 | |||||||||||||||
| 01-04-25 |
df2:和df1相同的日期索引,包含X、Y、Z三列,结构如下:
| X | Y | Z | |
|---|---|---|---|
| Date | |||
| 01-01-25 | |||
| 01-02-25 | |||
| 01-03-25 | |||
| 01-04-25 |
你的需求是:
- 将
df1中Capitals为B的所有Smalls列(Ba、Bb、Bc、Bd、Be)分别与df2的Z列相乘 - 将这5个结果列作为新的Capitals列D(对应Smalls的a、b、c、d、e)添加到
df1中,最终得到如下结构:
| Capitals | A | B | C | D | ||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Smalls | a | b | c | d | e | a | b | c | d | e | a | b | c | d | e | a | b | c | d | e |
| Date | ||||||||||||||||||||
| 01-01-25 | ||||||||||||||||||||
| 01-02-25 | ||||||||||||||||||||
| 01-03-25 | ||||||||||||||||||||
| 01-04-25 |
优化后的向量式方案
你当前使用的循环方法虽然可行,但pandas的向量化操作可以大幅简化代码,同时提升运行效率(尤其是数据量较大时)。具体代码如下:
# 提取df1中Capitals为B的所有列,与df2的Z列进行广播相乘 d_group = df1['B'] * df2['Z'].values[:, None] # 为结果设置多级列索引,保持和原df1一致的列名结构(Capitals='D',Smalls复用原有的a/b/c/d/e) d_group.columns = pd.MultiIndex.from_product( [['D'], d_group.columns], names=df1.columns.names ) # 将新的D组合并到原df1中 df1 = pd.concat([df1, d_group], axis=1)
代码解释:
- 提取并相乘:
df1['B']直接获取二级索引中Capitals为B的所有列,df2['Z'].values[:, None]将Z列转换为二维数组,实现和B组的每一列进行广播相乘(自动对齐行索引),这一步完全是向量化操作,没有循环。 - 设置多级索引:用
from_product快速生成新的多级列索引,确保和原df1的列结构一致,避免后续合并出现索引不匹配的问题。 - 合并DataFrame:用
pd.concat将新生成的D组合并到原df1,完成添加。
如果你的需求是除法(看你代码里写的是/ df2['Z']),只需要把乘法改成除法即可:
d_group = df1['B'] / df2['Z'].values[:, None]
对比原方案的优势
- 代码更简洁:去掉了创建空DataFrame、循环赋值的步骤,只用3行核心代码完成需求
- 效率更高:向量化操作是pandas底层优化的C语言实现,比Python循环快得多,数据量越大优势越明显
- 可读性更强:代码逻辑清晰,直接体现“提取B组→计算→合并”的流程
你当前的实现方法(供参考)
你原来的代码如下:
# Extract level 1 tickers from df1.columns smalls = df1.columns.get_level_values(1).unique() # Create new MultiIndex for the empty columns new_columns = pd.MultiIndex.from_product(['D', smalls],names=df1.columns.names) # Create an empty DataFrame with the new columns empty_df = pd.DataFrame(0, index=df1.index, columns=new_columns) # Concatenate with the original DataFrame df1 = pd.concat([df1, empty_df], axis=1) # Multiply dfs and populate D for small in smalls: df1[('D', small)] = df1[('B', small)] / df2['Z']
备注:内容来源于stack exchange,提问作者AndysPythonStuff
相关产品推荐
相关产品推荐

