如何基于DataFrame中MORELESS列的变化计算CHANGE列
实现DataFrame中CHANGE列的高效方法
问题背景
现有一个包含以下列的DataFrame:
- PRICE:正数数值列
- MORELESS:取值仅为1或-1,已通过当前行与上一行PRICE的大小关系计算完成(当前行PRICE更大则为1,更小则为-1)
需要生成第三列CHANGE,规则如下:
- 仅当MORELESS发生切换(从1变为-1或从-1变为1)时赋值,其余行留空
- 赋值公式:
100*(当前行PRICE - 上一次CHANGE发生行的PRICE)/上一次CHANGE发生行的PRICE
示例数据(Excel手动制作)
| INDEX | PRICE | MORELESS | CHANGE |
|---|---|---|---|
| 1 | 148,25 | ||
| 2 | 143,53 | -1 | -3,18 |
| 3 | 139,94 | -1 | |
| 4 | 139,00 | -1 | |
| 5 | 140,31 | 1 | -2,24 |
| 6 | 146,25 | 1 | |
| 7 | 145,81 | -1 | 3,92 |
| 8 | 144,59 | -1 | |
| 9 | 144,47 | -1 | |
| 10 | 146,53 | 1 | 0,49 |
| 11 | 145,34 | -1 | -0,81 |
| 12 | 145,31 | -1 | |
| 13 | 146,97 | 1 | 1,12 |
| 14 | 145,50 | -1 | -1,00 |
| 15 | 145,66 | 1 | 0,11 |
| 16 | 140,52 | -1 | -3,53 |
| 17 | 141,00 | 1 | 0,34 |
| 18 | 141,84 | 1 | |
| 19 | 139,44 | -1 | -1,11 |
| 20 | 135,81 | -1 | |
| 21 | 139,75 | 1 | 0,22 |
| 22 | 141,28 | 1 |
解决方案(基于Pandas矢量化操作)
采用矢量化操作替代循环,保证效率和简洁性:
import pandas as pd # 假设你的DataFrame名为df,先统一处理空值 df['MORELESS'] = df['MORELESS'].replace('', pd.NA) # 1. 标记MORELESS的变化点 # 对比当前行与上一行的MORELESS,不同则标记为True df['change_flag'] = df['MORELESS'] != df['MORELESS'].shift(1) # 第二行是第一个有效MORELESS,视为初始变化点(根据示例逻辑) df.loc[df.index[1], 'change_flag'] = True # 若DataFrame是0-based索引则用df.index[1],1-based则用1 # 2. 提取上一次变化点的PRICE并向前填充 # 仅在变化点保留PRICE,其余为NaN df['last_change_price'] = df['PRICE'].where(df['change_flag']) # 向前填充,得到每行对应的上一次变化点PRICE df['last_change_price'] = df['last_change_price'].ffill() # 3. 计算CHANGE列 df['CHANGE'] = df.apply( lambda row: round(100 * (row['PRICE'] - row['last_change_price']) / row['last_change_price'], 2) if row['change_flag'] else pd.NA, axis=1 ) # 4. (可选)清理中间辅助列 df = df.drop(['change_flag', 'last_change_price'], axis=1)
说明
- 矢量化操作避免了逐行循环,处理大数据集时效率更高
round(...,2)保证结果与示例一致,保留两位小数- 若你的DataFrame索引是0-based(默认),需注意调整第二行的标记逻辑
内容的提问来源于stack exchange,提问作者AndysPythonStuff
相关产品推荐
相关产品推荐

