簡體   English   中英

Pandas:使用從預先存在的列計算的值在數據框中創建兩個新列

[英]Pandas: create two new columns in a dataframe with values calculated from a pre-existing column

我正在使用pandas庫,我想將兩個新列添加到具有 n 列(n > 0)的數據框df
這些新列是將函數應用於數據幀中的列之一而產生的。

要應用的函數是這樣的:

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)

實現這一目標的最佳方法是什么? 我在沒有任何線索的情況下掃描了文檔

** df['column_A'].map(calculate)返回一個df['column_A'].map(calculate)系列,每個項目由一個元組 z, y 組成。 並嘗試將其分配給兩個數據框列會產生 ValueError.*

我只是使用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'])

第二種方法在較大的 DataFrame 上也快得多

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

用 300,000 行創建的 DataFrame

%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)

比 zip 快 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)

所以這是慢了兩倍,這並不是一個可怕的性能回歸,但是如果我們對上述內容進行 cythonize,我們會獲得更好的性能。 假設您正在使用 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

上面的例子應該清楚地展示了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)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM