为何第二个for循环无法为score2生成字段c及正确分数?
问题描述
尝试编写两个for循环,为不同输入计算分数并创建新字段存储该分数。第一个循环可正常运行,但第二个循环始终无法返回正确分数,甚至未生成字段c。
原代码
import pandas as pd d = {'a':['foo','bar'], 'b':[1,3]} df = pd.DataFrame(d) score1 = df.loc[df['a'] == 'foo'] score2 = df.loc[df['a'] == 'bar'] for i in score1['b']: if i < 3: score1['c'] = 0 elif i <= 3 and i < 4: score1['c'] = 1 elif i >= 4 and i < 5: score1['c'] = 2 elif i >= 5 and i < 8: score1['c'] = 3 elif i == 8: score1['c'] = 4 for j in score2['b']: if j < 2: score2['c'] = 0 elif j <= 2 and i < 4: score2['c'] = 1 elif j >= 4 and i < 6: score2['c'] = 2 elif j >= 6 and i < 8: score2['c'] = 3 elif j == 8: score2['c'] = 4 print(score1) print(score2)
运行结果
print(score1) a b c 0 foo 1 0 print(score2) a b 1 bar 3
问题原因
- 变量混淆错误:第二个循环的条件判断里,错误使用了第一个循环的变量
i而非当前循环的j。比如elif j <= 2 and i < 4,此时i是第一个循环的最后值(1),但j的值是3,所有条件都不满足,导致score2['c']从未被赋值。 - 冗余循环逻辑:
score1和score2各只有一行数据,完全没必要用for循环遍历,反而容易引发变量错误。 - 视图赋值隐患:
score1 = df.loc[df['a'] == 'foo']返回的是原DataFrame的切片视图,直接赋值可能触发SettingWithCopyWarning,属于不规范写法。
修复方案
方案1:修正变量并简化逻辑
把第二个循环里的所有i替换成j,同时去掉冗余的循环(直接取单值判断):
import pandas as pd d = {'a':['foo','bar'], 'b':[1,3]} df = pd.DataFrame(d) # 用copy()避免视图赋值问题 score1 = df.loc[df['a'] == 'foo'].copy() score2 = df.loc[df['a'] == 'bar'].copy() # 处理score1 i_val = score1['b'].iloc[0] if i_val < 3: score1['c'] = 0 elif 3 <= i_val < 4: score1['c'] = 1 elif 4 <= i_val < 5: score1['c'] = 2 elif 5 <= i_val < 8: score1['c'] = 3 elif i_val == 8: score1['c'] = 4 # 处理score2,修正变量和条件逻辑 j_val = score2['b'].iloc[0] if j_val < 2: score2['c'] = 0 elif 2 <= j_val < 4: score2['c'] = 1 elif 4 <= j_val < 6: score2['c'] = 2 elif 6 <= j_val < 8: score2['c'] = 3 elif j_val == 8: score2['c'] = 4 print(score1) print(score2)
方案2:用pandas矢量化操作(更推荐)
避免循环,用numpy.select实现批量判断,符合pandas的最佳实践:
import pandas as pd import numpy as np d = {'a':['foo','bar'], 'b':[1,3]} df = pd.DataFrame(d) # 定义foo的分数规则 foo_conditions = [ (df['a'] == 'foo') & (df['b'] < 3), (df['a'] == 'foo') & (3 <= df['b'] < 4), (df['a'] == 'foo') & (4 <= df['b'] < 5), (df['a'] == 'foo') & (5 <= df['b'] < 8), (df['a'] == 'foo') & (df['b'] == 8) ] foo_values = [0,1,2,3,4] # 定义bar的分数规则 bar_conditions = [ (df['a'] == 'bar') & (df['b'] < 2), (df['a'] == 'bar') & (2 <= df['b'] < 4), (df['a'] == 'bar') & (4 <= df['b'] < 6), (df['a'] == 'bar') & (6 <= df['b'] < 8), (df['a'] == 'bar') & (df['b'] == 8) ] bar_values = [0,1,2,3,4] # 合并规则并计算分数 all_conditions = foo_conditions + bar_conditions all_values = foo_values + bar_values df['c'] = np.select(all_conditions, all_values, default=np.nan) print(df.loc[df['a'] == 'foo']) print(df.loc[df['a'] == 'bar'])
修复后,score2会正确生成字段c,值为1。
内容的提问来源于stack exchange,提问作者SupaDupa
相关产品推荐
相关产品推荐

