当前位置: 首页 > 知识库问答 >
问题:

如何使用依赖于其他列的值有效地向dataframe添加多个列

濮阳驰
2023-03-14

我所拥有的:

  • 具有多行和多个现有列(python、pandas)的数据帧

我想做的事:

  • 向dataframe添加多个附加列,其中这些新列中的值都以某种方式依赖于同一行中现有列中的值

我已经有了下面的代码,它可以正常工作。然而,分析表明,这段代码是我代码中的一个重要瓶颈,因此如果可能的话,我想对其进行优化,我也有理由相信这应该是可能的:

df["NewColumn1"] = df.apply(lambda row: compute_new_column1_value(row), axis=1)
df["NewColumn2"] = df.apply(lambda row: compute_new_column2_value(row), axis=1)

# a few more lines of code like the above

我的解决方案基于对像这样的问题的回答(这是一个类似于我的问题,但特别是关于添加一个新列,而我的问题是关于添加许多新列)。我想这些df中的每一个。apply()调用在内部是通过一个遍历所有行的循环实现的,我想应该可以通过一个只遍历所有循环一次的解决方案(而不是我想添加的每列一次)来优化它。

在其他答案中,我看到了对assign()函数的引用,它确实支持一次添加多个列。我试着用以下方式使用它:

# WARNING: this does NOT work
df = df.assign(
    NewColumn1=lambda row: compute_new_column1_value(row),
    NewColumn2=lambda row: compute_new_column2_value(row),
    # more lines like the two above
)

这不起作用的原因是因为lambda实际上根本不接收数据帧的行作为参数,它们似乎只是一次获取整个数据帧。然后期望每个lambda一次返回完整的列/系列/数组值。所以,我这里的问题是,我必须通过那些lambda中的所有循环来实现手动循环,这显然会对性能造成更糟糕的影响。

我可以从概念上想到两种解决方案,但到目前为止还无法找到如何实际实施它们:

>

  • 类似于df。assign()(支持一次添加多个列),但能够将行传递到lambda而不是完整的数据帧中

    将我的compute\u new\u columnX\u value()函数矢量化的方法,以便它们可以像df那样用作lambda函数。assign()希望使用它们。

    到目前为止,第二种解决方案的问题是,我的一些函数的基于行的版本如下所示,我很难找到如何正确地对它们进行矢量化:

    def compute_new_column1_value(row):
        if row["SomeExistingColumn"] in some_dictionary:
            return some_dictionary[row["SomeExistingColumn"]]
        else:
            return some_default_value
    
  • 共有3个答案

    淳于博
    2023-03-14

    而不是试图将行标签引入。assign(),可以在链接之前对数据帧应用布尔掩码。将()赋值给它。下面的示例可以很容易地扩展到多个布尔条件和多个lambda,包括或不包括额外的for循环或if语句。

    import pandas as pd
    
    # Create data frame
    idx = np.arange(0, 10)
    rnd = pd.Series(np.random.randint(10, 20, 10))
    alpha_idx = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j']
    
    df = pd.DataFrame({'idx': idx, 'A': rnd, 'B': 100})
    df.index = alpha_idx
    
    # First assign() dependent on a boolean mask
    df_tmp = df[df['A'] < 15].assign(AmulB = lambda x: (x.A.mul(x.B)),
                   A_B = lambda x: x.B - x.A)
    
    # Second assign() dependent on a boolean mask
    df_tmp2 = df[df['A'] >= 15].assign(AmulB = lambda x: (x.A.div(x.B)),
                   A_B = lambda x: x.B + x.A)
    
    
    # Create a new df with different lambdas combined
    df_lambdas = df_tmp.append(df_tmp2)
    
    # Sort values
    df_lambdas.sort_values('idx', axis=0, inplace=True)
    print(df_lambdas)
    
        A    B  idx
    a  19  100    0
    b  17  100    1
    c  16  100    2
    d  13  100    3
    e  15  100    4
    f  10  100    5
    g  16  100    6
    h  15  100    7
    i  13  100    8
    j  10  100    9 
    
        A    B  idx  A_B    AmulB
    a  19  100    0  119     0.19
    b  17  100    1  117     0.17
    c  16  100    2  116     0.16
    d  13  100    3   87  1300.00
    e  15  100    4  115     0.15
    f  10  100    5   90  1000.00
    g  16  100    6  116     0.16
    h  15  100    7  115     0.15
    i  13  100    8   87  1300.00
    j  10  100    9   90  1000.00
    
    姬实
    2023-03-14

    如果您只需要检查50个条件,那么最好遍历这些条件并在块中填充单元格,而不是逐行遍历整个帧。顺便说一句assign()不仅接受lambda函数,而且代码的可读性也比我之前的建议要高得多。下面是一个修改版本,它也填充了额外的列。如果这个数据框有10000000行,我只想对A列中的10组数字范围应用不同的操作,这将是填充额外列的一种非常简洁的方法。

    import pandas as pd
    import numpy as np
    
    # Create data frame
    rnd = np.random.randint(1, 10, 10)
    rnd2 = np.random.randint(100, 1000, 10)
    df = pd.DataFrame(
            {'A': rnd, 'B': rnd2, 'C': np.nan, 'D': np.nan, 'E': np.nan })
    
    # Define different ways of filling the extra cells
    def f1():
        return df['A'].mul(df['B'])
    
    def f2():
        return np.log10(df['A'])
    
    def f3():
        return df['B'] - df['A']
    
    def f4():
        return df['A'].div(df['B'])
    
    def f5():
        return np.sqrt(df['B'])
    
    def f6():
        return df['A'] + df['B']
    
    # First assign() dependent on a boolean mask
    df[df['A'] < 50] = df[df['A'] < 15].assign(C = f1(), D = f2(), E = f3())
    
    # Second assign() dependent on a boolean mask
    df[df['A'] >= 50] = df[df['A'] >= 50].assign(C = f4(), D = f5(), E = f6())
    
    print(df)
    
         A      B       C         D    E
    0  4.0  845.0  3380.0  0.602060  841
    1  3.0  967.0  2901.0  0.477121  964
    2  3.0  468.0  1404.0  0.477121  465
    3  2.0  548.0  1096.0  0.301030  546
    4  3.0  393.0  1179.0  0.477121  390
    5  7.0  741.0  5187.0  0.845098  734
    6  1.0  269.0   269.0  0.000000  268
    7  4.0  731.0  2924.0  0.602060  727
    8  4.0  193.0   772.0  0.602060  189
    9  3.0  306.0   918.0  0.477121  303
    
    鲁钱明
    2023-03-14

    您是否尝试过将列初始化为nan,按行遍历数据框,并使用loc赋值?

    import numpy as np
    import pandas as pd
    
    df = pd.DataFrame(np.random.randint(0, 20, (10, 5)))
    
    df[5] = np.nan
    df[6] = np.nan
    
    for i, row in df.iterrows():
        df.loc[i, 5] = row[1] + row[4]
        df.loc[i, 6] = row[3] * 2
    
    print(df)
    

    产量

        0   1   2   3   4
    0  17   4   3  11  10
    1  16   1  14  11  16
    2   4  18  12  19   7
    3  11   3   7  10   5
    4  11   0  10   1  17
    5   5  17  10   3   8
    6   0   0   7   3   6
    7   7  18  18  13   8
    8  16   4  12  11  16
    9  13   9  15   8  19
    
        0   1   2   3   4     5     6
    0  17   4   3  11  10  14.0  22.0
    1  16   1  14  11  16  17.0  22.0
    2   4  18  12  19   7  25.0  38.0
    3  11   3   7  10   5   8.0  20.0
    4  11   0  10   1  17  17.0   2.0
    5   5  17  10   3   8  25.0   6.0
    6   0   0   7   3   6   6.0   6.0
    7   7  18  18  13   8  26.0  26.0
    8  16   4  12  11  16  20.0  22.0
    9  13   9  15   8  19  28.0  16.0
    
     类似资料:
    • 那么,如何使用PySpark向现有的DataFrame添加一个新列(基于Python vector)呢?

    • 初始数据流: 产生的数据frame: 我通常通过使用以下内容将新列“追加”到dataframe:

    • 问题内容: 我在尝试获取另一列中的字符串值的字符计数列时遇到问题,但还没有弄清楚如何有效地做到这一点。 显然,这涉及首先创建一个null列,然后将其重写,这对我的数据集要花费很长时间。那么获得这样的东西最有效的方法是什么 我已经检查了很多,但是还无法弄清楚。 问题答案: Pandas为此使用了矢量化字符串方法:。要创建新列,您可以编写: 例如: 这应该比使用Python循环在DataFrame上循

    • 假设我有两个表,表A和表B,它们有一对多的关系。 col1 | Col2 Col1|Col3 现在,我希望表a中有一个Col4,如果对于给定的Col1值,Col3的任何一行都为true,那么我希望表a中的Col4设置为true,否则为false。 表B上发生的所有更新都应始终更新表A中的Col4值。 使用任何oracle/PL-SQL特性都可以做到这一点吗?

    • 几个小时以来,我一直试图找到一种方法来复制n次列,并为它们添加一个,但运气不佳。请帮帮忙! 当前数据帧: 输出:

    • 在我的scala程序中,我有一个dataframe,其中有两列和(类型都为)。除此之外,我有一个先前定义的对象和一些方法和属性。在这里,我想要使用dataframe的当前值和中的属性向dataframe添加一个新列。 例如,如果我有下面的dataframe: 谢谢你。