微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

如何使用依赖于其他列的值有效地向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

我将此解决方案基于this one这样的问题的答案(这是一个类似于我的问题,但具体是关于添加一个新列,而我的问题是添加许多新列).我想这些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一次返回完整的列/ Series /数组值.所以,我的问题是,我必须最终在这些lambda中通过所有循环实现手动循环,这显然会对性能更糟.

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

>类似于df.assign()(支持一次添加多个列),但能够将行传递到lambda而不是完整的数据帧
>一种向我的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

解决方法:

如果你只有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

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 [email protected] 举报,一经查实,本站将立刻删除。

相关推荐