2 回答
TA贡献1831条经验 获得超4个赞
已经解释了为什么您对 NA 列的比较没有返回您期望的结果。
但是,我会以与他不同的方式进行比较。这是一个小片段,应该可以帮助您理解:
# a series of bools, indicating for which index our condition is true
na_gt_1_series = df["NA"] > 1
print(na_gt_1)
# creating a new column based on the values of the NA column
df["na_gt_1"] = na_gt_1_series
print(df)
现在,由于这里的条件相当复杂,我认为使用 pandas 的 apply 函数会更简单,它沿着 DataFrame 的某个轴应用一个函数。
def get_row_df5(row):
df5 = 0
if row["NA"] > 1:
if row["MULT"] == 1:
if row["NOB"] == 1:
df5 = -A1 * row["NOB"]
else:
df5 = -A2 * row["NOB"] - B * (row["NOA"] - row["NOB"])
elif row["NA"] == 1:
if row["MULT"] == 1:
if row["EX"] == 0 and row["NOB"] == 4 and row["CHARGE"] == 0:
df5 = -A1 * row["NOB"]
elif row["NOB"] != 1 or row["NOB"] == 1 and row["EX"] != 0:
df5 = -C * row["NOB"]
elif row["NOB"] == 1 and row["EX"] == 0:
df5 = -E * row["NOB"]
else:
df5 = -C * row["NOB"] - D * (row["NOA"] - row["NOB"])
return df5
df5_res = df.apply(func=get_row_df5, axis=1)
不幸的是,这种简单性是有代价的。对于通过复制示例数据制作的 120,000 行 DataFrame,应用解决方案需要约 4 秒,而以下解决方案需要约 40 毫秒(快 100 倍)。
def get_df5_broad(df_in):
na_lt_1 = df_in["NA"] > 1
na_eq_1 = df_in["NA"] == 1
mult_eq_1 = df_in["MULT"] == 1
mult_ne_1 = ~mult_eq_1
res_series = pd.Series(np.zeros(shape=df_in.shape[0]))
res_series.loc[na_lt_1 & mult_eq_1 & (df_in["NOB"] == 1)] = -A1 * df_in["NOB"]
res_series.loc[na_lt_1 & mult_ne_1] = -A2 * df_in["NOB"] - B * (df_in["NOA"] - df_in["NOB"])
res_series.loc[na_eq_1 & mult_eq_1 & (df_in["EX"] == 0) & (df_in["NOB"] == 4) & (df_in["CHARGE"] == 0)] = -A1 * df_in["NOB"]
res_series.loc[na_eq_1 & mult_eq_1 & ((df_in["NOB"] != 1) | ((df_in["NOB"] == 1) & (df_in["EX"] != 0)))] = -C * df_in["NOB"]
res_series.loc[na_eq_1 & mult_eq_1 & (df_in["NOB"] == 1) & (df_in["EX"] == 0)] = -E * df_in["NOB"]
res_series.loc[na_eq_1 & mult_ne_1] = -C * df_in["NOB"] - D * (df_in["NOA"] - df_in["NOB"])
return res_series
最后,下一个方法是两全其美的方法。它的设计和简单性与使用 apply 的方法相似,但仅比之前的高性能版本慢 5 倍。
def get_df5_tupe(tupe):
df5 = 0
if tupe.NA > 1:
if tupe.MULT == 1:
if tupe.NOB == 1:
df5 = -A1 * tupe.NOB
else:
df5 = -A2 * tupe.NOB - B * (tupe.NOA - tupe.NOB)
elif tupe.NA == 1:
if tupe.MULT == 1:
if tupe.EX == 0 and tupe.NOB == 4 and tupe.CHARGE == 0:
df5 = -A1 * tupe.NOB
elif tupe.NOB != 1 or tupe.NOB == 1 and tupe.EX != 0:
df5 = -C * tupe.NOB
elif tupe.NOB == 1 and tupe.EX == 0:
df5 = -E * tupe.NOB
else:
df5 = -C * tupe.NOB - D * (tupe.NOA - tupe.NOB)
return df5
def get_df5_iter(df_in):
return pd.Series((get_df5_tupe(curr) for curr in df_in.itertuples(index=False)))
注意:由于 OP 中的逻辑歧义,这些方法并不总是返回正确的答案。一旦正确的布尔表达式可用,我将立即编辑我的解决方案。
TA贡献1806条经验 获得超5个赞
这个块在这里:
if (df['NA'] > 1).any():
print(True)
elif (df['NA'] == 1).any():
print(False)
将始终打印 True 因为列 'NA' 的值大于 1,因此不会评估第二个 elif。根据您的评论,如果我没记错的话,我认为您想遍历 DataFrame 并评估每个元素。你可以尝试这样的事情:
for val in df['NA']:
if val > 1:
print(True)
elif val == 1:
print(False)
这将评估列“NA”的每个元素,对于您的实际用例,您将想知道给定 val 的索引,这可以使用enumerate. 例如:
for (idx, val) in enumerate(df['NA']):
if val > 1:
d5 = -A1 * df['NOB'].iloc[idx]
elif val == 1:
d5 = E * df['NOB'].iloc[idx]
idx是当前元素的索引,您可以使用 访问该索引处其他列的元素iloc。我希望这会有所帮助,祝你好运。
添加回答
举报