Python:循环中对 IF 语句的不一致处理
Posted
技术标签:
【中文标题】Python:循环中对 IF 语句的不一致处理【英文标题】:Python: inconsistent handling of IF statement in loop 【发布时间】:2020-12-24 16:09:34 【问题描述】:我有一个包含条件和值的数据框df
。
import pandas as pd
df=pd.DataFrame('COND':['X','X','X','Y','Y','Y'], 'VALUE':[1,2,3,1,2,3])
因此df
看起来像:
COND VALUE
X 1
X 2
X 3
Y 1
Y 2
Y 3
我正在使用循环根据COND
对df
进行子集化,并编写包含每个条件值的单独文本文件
conditions = 'X','Y'
for condition in conditions:
df2 = df[df['COND'].isin([condition])][['VALUE']]
df2.to_csv(condition + '_values.txt', header=False, index=False)
最终结果是两个文本文件:X_vals.txt 和 Y_vals.txt,这两个文件都包含1 2 3
。到目前为止,一切都按预期工作。
我想进一步子集df
仅用于一个条件。例如,也许我想要条件 Y 中的所有值,但只有条件 X 中的值 1 2,而 Y_vals.txt 应该包含 1 2 3
。我尝试使用 IF 语句来实现这一点:
conditions = 'X','Y'
for condition in conditions:
if condition == 'X':
df = df[df['VALUE'] < 3]
df2 = df[df['COND'].isin([condition])][['VALUE']]
df2.to_csv(condition + '_values.txt', header=False, index=False)
这就是不一致发生的地方。上面的代码工作正常(即 X_vals.txt 包含1 2
,和 Y_vals.txt 1 2 3
,正如预期的那样),但是当我使用if condition=='Y'
而不是if condition=='X'
时,它会中断,并且两个文本文件都只包含@ 987654337@.
换句话说,如果我在 IF 语句中指定 conditions
的第一个元素,那么它会按预期工作,但是如果我指定第二个元素,那么它会中断并将
这是怎么回事,我该如何解决?
谢谢!
【问题讨论】:
df = df[df['VALUE'] < 3]
您在循环中更改了初始数据框 - 那是您的错误
【参考方案1】:
您遇到的问题是因为您在循环内覆盖了df
。
conditions = 'X','Y'
for condition in conditions:
if condition == 'X':
df = df[df['VALUE'] < 3] # <-- HERE'S YOUR ISSUE
df2 = df[df['COND'].isin([condition])][['VALUE']]
df2.to_csv(condition + '_values.txt', header=False, index=False)
让我有点惊讶的是,当你循环遍历集合 conditions
时,你首先得到 condition = 'Y'
,然后 condition = 'X'
。但是作为一个集合是一个无序集合(即它没有声称它的元素具有固有的顺序),这不应该太令人不安:python 只是读取元素的最内部方便的方式。
您可以使用conditions = ['X', 'Y']
来循环遍历列表(有序集合)。然后它将先执行 X,然后执行 Y。但是,如果您这样做,您将得到相同的错误,但相反(即它适用于 if condition == 'Y'
,但不适用于 if condition == 'X'
)。
这是因为循环运行一次后,df
已重新分配给原始 df
的子集,该子集仅包含小于 3 的值。这就是为什么如果if condition
语句在第一次通过循环时触发,那么您在两个文件中都只能得到值 1 和 2。
现在进行修复:
conditions = ['X', 'Y']
for condition in conditions:
csv_name = f"condition_values.txt"
if condition == 'X':
df_filter = f"VALUE < 3 & COND == 'condition'"
else:
df_filter = f"COND == 'condition'"
df.query(df_filter).VALUE.to_csv(csv_name, header=False, index=False)
在这里我介绍了DataFrame.query
方法,它通常比尝试创建一个布尔系列用作掩码更简洁。
f-string 语法仅适用于 python 3.6+,如果您使用的是较低版本,请酌情修改(例如df_filter = "COND == ''".format(condition)
)
【讨论】:
感谢您的详尽回答!您能否说明如何使用 f-string 适应每行的较低版本? 这就是我最后一行示例的意思。格式化字符串有多种方法,但其中一种方法是字符串的format
方法。在每种情况下,只需删除 f
前缀并将 .format(condition=condition)
放在字符串的末尾。或者,为简洁起见,.format(condition)
并将 condition
更改为
,如我的示例所示。【参考方案2】:
df=pd.DataFrame('COND':['X','X','X','Y','Y','Y'], 'VALUE':[1,2,3,1,2,3])
conditions = df.COND
for condition in conditions:
print(condition)
df2=df[df['COND'].isin([condition])][['VALUE']]
df2.to_csv(condition + '_values.txt',header=False, index=False)
for condition in conditions:
if condition=='X':
df=df[df['VALUE'] < 3]
df2=df[df['COND'].isin([condition])][['VALUE']]
df2.to_csv(condition + '_values.txt',header=False, index=False)
您没有指定变量“条件”,所以它给了您一个错误。 尝试做:
条件 = df.COND
在for循环之前
【讨论】:
糟糕 - 我最初将条件定义为 conditions='X','Y' (已编辑以包含此内容)但您的回答揭示了一些新的东西。使用 conditions='X','Y' 定义条件会导致我描述的问题,但是按照您的建议使用 conditions=df.COND 会导致代码每次都失败 - 也就是说,无论如何,所有 df 总是被子集化我在 IF 语句中使用哪个条件。有趣...【参考方案3】:我们可以将条件写入dict
,然后使用map
过滤groupby
之前的df
cond = 'X' : 2, 'Y' : 3
subdf = df[df['VALUE']<df.COND.map(cond)]
for x, y in subdf.groupby('COND'):
y.to_csv(x + '_values.txt')
【讨论】:
感谢您提供此解决方法,但是我真的想了解现有代码有什么问题。我正在使用一个脚本,它使用我上面描述的更复杂的版本,所以我需要知道这里出了什么问题以上是关于Python:循环中对 IF 语句的不一致处理的主要内容,如果未能解决你的问题,请参考以下文章