如何遍历DataFrame并基于前置条件(含前置新增值)添加方向列
问题解决:基于DataFrame生成direction列
原始数据与需求
首先定义目标DataFrame:
import pandas as pd df = pd.DataFrame({'timestamp': [123, 456, 789, 101112, 131415, 161718, 192021, 222324, 252627, 282930, 313233, 343536], 'value': ["", "", "", 68, 47, 62, 62, 62, 62, 54, 54 , 54]})
需要生成第三列direction,规则如下:
- 若
value为空,则direction为空; - 若
value> 前一行value,则direction= "positive"; - 若
value< 前一行value,则direction= "negative"; - 若
value= 前一行value且 前一行direction为"positive",则direction= "positive"; - 若
value= 前一行value且 前一行direction为"negative",则direction= "negative";
尝试的方法及问题
1. 循环遍历代码
for i in range(len(df)): if i == 0 : if df.iloc[i-1,'value'] > df.iloc[i,'value']: df.iloc[i,'direction'] = "positive"
报错:ValueError: Can only index by location with a [integer, integer slice (START point is INCLUDED, END point is EXCLUDED), listlike of integers, boolean array]
问题:iloc仅支持位置索引,不能传入列名;且i=0时i-1=-1会触发索引越界。
2. 另一种循环代码
for i in range(1, len(df) + 1): col = 'value' j = df.columns.get_loc('direction') if (df[col] > (df[col].shift(1))): df.loc[i - 1, j] = "positive" elif (df[col] < (df[col].shift(1))): df.loc[i - 1, j] = "negative"
报错:ValueError: The truth value of a Series is ambiguous. Use a.empty, a.bool(), a.item(), a.any() or a.all().
问题:直接用Series做if判断会触发歧义,因为Series包含多个布尔值,无法直接判断真假。
3. 使用np.where
import numpy as np df['positive'] = np.where( (df['value'] > df['value'].shift(1)) , "1", "") df['negative'] = np.where( (df['value'] < df['value'].shift(1)) , "1", "") df['positive2'] = np.where( (df['positive'].shift(1) =="1") & (df['value'] == df['value'].shift(1)), "1", "0") df['negative2'] = np.where( (df['negative'].shift(1) =="1") & (df['value'] == df['value'].shift(1)), "1","0")
问题:无报错但未实现预期效果,因为np.where是矢量化操作,无法依赖前一行的direction计算结果,无法处理连续相等值的继承逻辑。
解决方案
由于逻辑依赖前一行的计算结果,逐行循环是最直接的实现方式,步骤如下:
import pandas as pd # 初始化DataFrame df = pd.DataFrame({'timestamp': [123, 456, 789, 101112, 131415, 161718, 192021, 222324, 252627, 282930, 313233, 343536], 'value': ["", "", "", 68, 47, 62, 62, 62, 62, 54, 54 , 54]}) # 将value列转为数值类型,空字符串转为NaN df['value'] = pd.to_numeric(df['value'], errors='coerce') # 初始化direction列 df['direction'] = "" # 逐行遍历处理 for i in range(1, len(df)): # 当前value为空(NaN)时,保持direction为空 if pd.isna(df.loc[i, 'value']): continue # 前一行value为空时,无对比基准,保持direction为空 if pd.isna(df.loc[i-1, 'value']): continue # 数值比较逻辑 if df.loc[i, 'value'] > df.loc[i-1, 'value']: df.loc[i, 'direction'] = "positive" elif df.loc[i, 'value'] < df.loc[i-1, 'value']: df.loc[i, 'direction'] = "negative" else: # 值相等时,继承前一行的direction df.loc[i, 'direction'] = df.loc[i-1, 'direction']
处理后结果
| timestamp | value | direction |
|---|---|---|
| 123 | NaN | |
| 456 | NaN | |
| 789 | NaN | |
| 101112 | 68 | |
| 131415 | 47 | negative |
| 161718 | 62 | positive |
| 192021 | 62 | positive |
| 222324 | 62 | positive |
| 252627 | 62 | positive |
| 282930 | 54 | negative |
| 313233 | 54 | negative |
| 343536 | 54 | negative |
方案说明
- 先将
value列转为数值类型,空字符串转为NaN,方便空值判断和数值比较; - 初始化
direction列为空字符串; - 从第2行(索引1)开始遍历,针对不同场景处理:
- 当前值或前一行值为空时,保持
direction为空; - 数值大小对比后设置对应
direction; - 值相等时直接继承前一行的
direction,完全符合需求。
- 当前值或前一行值为空时,保持
内容的提问来源于stack exchange,提问作者chouchou
相关产品推荐
相关产品推荐

