【问题标题】:Conditional statement to generate multi-column values in Python在 Python 中生成多列值的条件语句
【发布时间】:2021-09-22 21:16:27
【问题描述】:

我正在尝试根据以下数据框中一列“数字”中的条件替换“Alloc1”和“Alloc2”列中的值。

data = {'ID': ['001', '002', '003', '004'], 'Number': [99, 99, 20, 40], 'Alloc1': [np.NaN, np.NaN, np.NaN, np.NaN], 'Alloc2': [np.NaN, np.NaN, np.NaN, np.NaN]}
# Create DataFrame.
df = pd.DataFrame(data)

我根据条件插入值的代码如下:-

for  numbers  in df["Number"]:
    
    if  (numbers == 99):
        df["Alloc1"] = 31
        df["Alloc2"] = 3

    else:
        df["Alloc1"] = 0
        df["Alloc2"] = numbers/2 

上面似乎只执行了语句的 else 部分,并且“数字”列中的最后一个值不是 99。我该如何解决这个问题?一个功能会很棒。理想的输出应该是:-

final = {'ID': ['001', '002', '003', '004'], 'Number': [99, 99, 20, 40], 'Alloc1': [31, 31, 0, 0], 'Alloc2': [3, 3, 10, 20]}
# Create DataFrame.
final_df = pd.DataFrame(final)

【问题讨论】:

  • 在您的预期输出中,Alloc2 是否应该具有值 3, 3, 10, 20 而不是 3, 3, 2, 2?逻辑暗示如果Number不是99,则设置Alloc2 = Number / 2
  • df["Alloc1"] = 31整列分配给一个常量。您只需将某一行(数字来自的同一行)中的值分配给新值。然而,更好的方法是np.where
  • 感谢@PeterLeimbigler 的更正。已编辑。

标签: python pandas dataframe


【解决方案1】:

认为“矢量化”解决方案将具有比这更好的性能,并且那个或where 版本都更“好的熊猫风格”。这个答案只是为了向您展示如何使用更像您所遵循的方法来实现您想要的。这不是一种非常“熊猫”的做事方式,但可能有助于理解为什么您尝试的方法不起作用。

import pandas as pd

data = {'ID': ['001', '002', '003', '004'],
        'Number': [99, 99, 20, 40]}
        # Don't actually need the NaN-filled 'Alloc1' and 'Alloc2' yet
        # Those columns get created when you give them values, later
df = pd.DataFrame(data)

def allocateCodes(row):
    if (row['Number'] == 99):
        row['Alloc1'] = 31
        row['Alloc2'] = 3
    else:
        row['Alloc1'] = 0
        row['Alloc2'] = row['Number'] / 2
    return row

# axis="columns" means go 'take each row' (i.e., a whole set of columns)
# at a time (can also use axis=1)
# instead of 'take each column' (axis="rows" / axis=0)      
outputDf = df.apply(allocateCodes, axis="columns")

print(outputDf)

输出:

    ID  Number  Alloc1  Alloc2
0  001      99      31     3.0
1  002      99      31     3.0
2  003      20       0    10.0
3  004      40       0    20.0

【讨论】:

  • 非常感谢您采用这种方法。它实际上反映了我的思维过程。
【解决方案2】:

假设您可以安全地覆盖整个列 Alloc1Alloc2,您可以按照 Henry Ecker 的建议使用 np.where

df['Alloc1'] = np.where(df['Number'] == 99, 31, 0)
df['Alloc2'] = np.where(df['Number'] == 99, 3, df['Number'] / 2).astype(int)

print(df)
    ID  Number  Alloc1  Alloc2
0  001      99      31       3
1  002      99      31       3
2  003      20       0      10
3  004      40       0      20

【讨论】:

  • 这比我的优雅多了,太棒了。
  • 感谢彼得的解决方案。效果也很好。
  • 感谢@BaronLegendre。您的解决方案的优点是读者无需考虑np.where 的工作原理:)
【解决方案3】:

尝试使用矢量化操作来处理这个问题

import pandas as pd

data = {'ID': ['001', '002', '003', '004'], 'Number': [99, 99, 20, 40], 'Alloc1': [np.NaN, np.NaN, np.NaN, np.NaN], 'Alloc2': [np.NaN, np.NaN, np.NaN, np.NaN]}
# Create DataFrame.
df = pd.DataFrame(data)

df['Alloc1'] = 0
df['Alloc2'] = df['Number']/2
df.loc[df['Number'] == 99,'Alloc1'] = 31
df.loc[df['Number'] == 99,'Alloc2'] = 3
df
output
    ID  Number  Alloc1  Alloc2
0  001      99      31     3.0
1  002      99      31     3.0
2  003      20       0    10.0
3  004      40       0    20.0

【讨论】:

  • 感谢 Baron 的解决方案。效果也很好。
猜你喜欢
  • 2018-04-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-10-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-03-04
相关资源
最近更新 更多