为了账号安全,请及时绑定邮箱和手机立即绑定

比较python中单列pandas数据框的值(将perl转换为python代码)

比较python中单列pandas数据框的值(将perl转换为python代码)

三国纷争 2022-06-22 18:26:11
我正在尝试将 perl 代码转换为 python,以便将列简单地乘以一些常量。我创建了一个带有多列浮点值的 pandas 数据框。这是 components.csv 文件的示例。      NA  MULT   NOA   NOB  CHARGE   EX0    8.0   1.0  24.0  24.0     0.0  1.01    8.0   1.0  24.0  24.0     0.0  1.02    8.0   1.0   6.0   6.0     0.0  1.03   20.0   1.0  18.0  18.0     0.0  1.04   23.0   1.0  21.0  21.0     0.0  1.05   26.0   1.0  24.0  24.0     0.0  1.06   11.0   1.0  13.0  13.0     0.0  0.07   16.0   1.0  19.0  19.0     1.0  0.08    1.0   1.0   4.0   4.0    -1.0  0.09   17.0   1.0  23.0  23.0     0.0  0.010   1.0   1.0   4.0   4.0     0.0  0.011   1.0   1.0   4.0   4.0     0.0  0.0初始参数为:$A1 = 9.3692400791;$A2 = 9.4492960287;$B  = 3.8320915550;$C  = 9.5936653352;$D  = 1.8739215238;$E  = 2.4908584058;预期的输出是单列(d5):Df5-0.2249-0.2249-0.0562-0.1686-0.1968-0.2249-0.1218-0.1780-0.0384-0.2155-0.0375-0.0375使用以下方法解析数据帧后:pd.set_option('precision', 8)df = pd.read_csv("unscaled_components_delimit.csv", delimiter= ",", header=0)我有多个条件要检查,例如以下脚本:if (df['NA'] > 1).any():    print(True)elif (df['NA'] == 1).any():    print(False)然而,上面的代码只打印一个 True 值,即使在标题为 NA 的列中有多个 1.0 值,这意味着它不会传递给第二个 elif。我使用了函数 any() ,也许应该使用我目前不知道的另一个函数。因此,有人可能会为此提出解决方案吗?目标是将列(标题 NA)的每个元素与数字 1(大于或等于)进行比较。然后,对其他列执行一些具有其他条件的操作。我将不胜感激任何帮助或建议。为了更清楚起见,以下代码包含具有所有必需条件的最终所需代码:if (df['NA'] > 1).any():    if (df['MULT'] == 1).any():        if ((df['NOB'] != 1).any() or (df['NOB'] ==1).any()):            d5 = -A1*df['NOB']        elif((df['NOB'] == 1).any()):            d5 = -E*df['NOB']    else:        d5 = -A2*df['NOB'] - B*(df['NOA']-df['NOB'])
查看完整描述

2 回答

?
慕容708150

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 中的逻辑歧义,这些方法并不总是返回正确的答案。一旦正确的布尔表达式可用,我将立即编辑我的解决方案。


查看完整回答
反对 回复 2022-06-22
?
忽然笑

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。我希望这会有所帮助,祝你好运。


查看完整回答
反对 回复 2022-06-22
  • 2 回答
  • 0 关注
  • 143 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信