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

Den*_*ers 6 python dataframe pandas

是)我有的:

  • 一个包含许多行的数据帧,以及几个现有列(python,pandas).
  • Python 3.6,所以依赖于特定版本的解决方案对我来说很好(但显然也适用于早期版本的解决方案也很好)

我想做的事:

  • 向数据框添加多个附加列,其中这些新列中的值都取决于同一行中现有列中的值的某些方式.
  • 必须保留数据帧的原始顺序.如果解决方案改变了排序,我可以通过基于其中一个现有列手动排序来恢复它,但显然这会带来额外的开销.

我已经有以下代码,它可以正常工作.但是,分析表明此代码是我的代码中的重要瓶颈之一,所以我想尽可能优化它,我也有理由相信应该是可能的:

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
Run Code Online (Sandbox Code Playgroud)

我基于这个答案解决这样的问题这一个(这是与我相似,但具体如何添加一个新列的问题,而我的问题是关于添加了许多新的列).我想这些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
)
Run Code Online (Sandbox Code Playgroud)

这不起作用的原因是因为lambda实际上根本没有接收到数据帧的行,它们似乎只是立刻得到整个数据帧.然后期望每个lambda一次返回完整的列/ Series /数组值.所以,我的问题是,我必须最终在这些lambda中通过所有循环实现手动循环,这显然会对性能更糟.

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

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

  2. 一种向我的compute_new_columnX_value()函数进行向量化的方法,以便它们可以像df.assign()预期的那样用作lambda .

到目前为止我的第二个解决方案的问题是基于行的版本我的一些函数看起来如下,我很难找到如何正确地向量化它们:

def compute_new_column1_value(row):
    if row["SomeExistingColumn"] in some_dictionary:
        return some_dictionary[row["SomeExistingColumn"]]
    else:
        return some_default_value
Run Code Online (Sandbox Code Playgroud)

KRK*_*rov 2

如果您只有 50 个条件要检查,那么最好迭代条件并填充块中的单元格,而不是逐行遍历整个框架。顺便说一句, .assign() 不仅接受 lambda 函数,而且代码也可以比我之前的建议更具可读性。下面是一个修改版本,它还填充了额外的列。如果这个数据框有 10,000,000 行,并且我只想对 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
Run Code Online (Sandbox Code Playgroud)


归档时间:

查看次数:

2017 次

最近记录:

7 年,9 月 前