Pandas:在dataframe中创建两个新列,其中的值由预先存在的列计算得出

2024-05-16 00:46:03 发布

您现在位置:Python中文网/ 问答频道 /正文

我正在使用pandas库,我想将两个新列添加到具有n列(n>;0)的数据帧df 这些新列是对dataframe中的一列应用函数的结果。

应用的功能如下:

def calculate(x):
    ...operate...
    return z, y

为只返回值的函数创建新列的一种方法是:

df['new_col']) = df['column_A'].map(a_function)

所以,我想要的,并且尝试失败的,是像:

(df['new_col_zetas'], df['new_col_ys']) = df['column_A'].map(calculate)

实现这一目标的最佳方法是什么?我毫无头绪地扫描了一下documentation

**df['column_A'].map(calculate)返回一个pandas系列,每个项由一个元组z,y组成。如果试图将其分配给两个dataframe列,则会产生一个ValueError.*


Tags: 数据方法函数gt功能mapdataframepandas
2条回答

我就用zip

In [1]: from pandas import *

In [2]: def calculate(x):
   ...:     return x*2, x*3
   ...: 

In [3]: df = DataFrame({'a': [1,2,3], 'b': [2,3,4]})

In [4]: df
Out[4]: 
   a  b
0  1  2
1  2  3
2  3  4

In [5]: df["A1"], df["A2"] = zip(*df["a"].map(calculate))

In [6]: df
Out[6]: 
   a  b  A1  A2
0  1  2   2   3
1  2  3   4   6
2  3  4   6   9

在我看来,最高答案是有缺陷的。希望没有人用from pandas import *将所有熊猫大量导入其名称空间。此外,在传递字典或序列时,map方法应保留给那些时间。它可以接受一个函数,但这就是apply的用途。

所以,如果你一定要用上面的方法,我会这样写

df["A1"], df["A2"] = zip(*df["a"].apply(calculate))

实际上没有理由在这里使用zip。您只需执行以下操作:

df["A1"], df["A2"] = calculate(df['a'])

第二种方法在较大的数据帧上也要快得多

df = pd.DataFrame({'a': [1,2,3] * 100000, 'b': [2,3,4] * 100000})

用300000行创建的数据帧

%timeit df["A1"], df["A2"] = calculate(df['a'])
2.65 ms ± 92.4 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

%timeit df["A1"], df["A2"] = zip(*df["a"].apply(calculate))
159 ms ± 5.24 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)

比拉链快60倍


一般情况下,避免使用apply

Apply通常不会比遍历Python列表快多少。让我们测试for循环的性能,以执行与上面相同的操作

%%timeit
A1, A2 = [], []
for val in df['a']:
    A1.append(val**2)
    A2.append(val**3)

df['A1'] = A1
df['A2'] = A2

298 ms ± 7.14 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

所以这是两倍的速度,这不是一个糟糕的性能回归,但是如果我们把上面的方法化,我们会得到更好的性能。假设您使用的是ipython:

%load_ext cython

%%cython
cpdef power(vals):
    A1, A2 = [], []
    cdef double val
    for val in vals:
        A1.append(val**2)
        A2.append(val**3)

    return A1, A2

%timeit df['A1'], df['A2'] = power(df['a'])
72.7 ms ± 2.16 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)

直接分配而不应用

如果使用直接矢量化操作,您可以获得更大的速度改进。

%timeit df['A1'], df['A2'] = df['a'] ** 2, df['a'] ** 3
5.13 ms ± 320 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

这利用了NumPy极其快速的矢量化操作,而不是我们的循环。现在我们的速度比原来提高了30倍。


最简单的速度测试

上面的例子应该清楚地显示出apply的速度有多慢,但是让我们看看最基本的例子。让我们把一系列1000万的数字加上和不加上

s = pd.Series(np.random.rand(10000000))

%timeit s.apply(calc)
3.3 s ± 57.4 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

不使用比使用快50倍

%timeit s ** 2
66 ms ± 2 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)

相关问题 更多 >