Python vượt qua hàng khung dữ liệu để hoạt động

Hơn 3 năm trước, chúng tôi đã đăng một nghiên cứu so sánh về việc lặp lại dữ liệu Pandas bằng CPU. Bởi vì rất nhiều thứ đã phát triển kể từ năm 2018, bài đăng này là một bản cập nhật. Ví dụ phiên bản thẻ Pandas lúc đó là

from itertools import cycle
from time import perf_counter

import cython
import dask.dataframe as dd
from numba import jit, float64, njit, prange
import numpy as np
import perfplot
import pandas as pd
import polars as pl
import swifter

%load_ext Cython
%load_ext line_profiler

SD = 124  # random seed
rng = np.random.default_rng[SD]  # random number generator
11, bây giờ là
from itertools import cycle
from time import perf_counter

import cython
import dask.dataframe as dd
from numba import jit, float64, njit, prange
import numpy as np
import perfplot
import pandas as pd
import polars as pl
import swifter

%load_ext Cython
%load_ext line_profiler

SD = 124  # random seed
rng = np.random.default_rng[SD]  # random number generator
12. Ngoài ra, chúng tôi đã thêm một số tùy chọn khác

Dưới đây là danh sách tất cả các tùy chọn được thử nghiệm sau đây

  • Pandas tích hợp vector hóa
  • gấu trúc. Khung dữ liệu. lặp đi lặp lại
  • gấu trúc. Khung dữ liệu. ứng dụng
  • gấu trúc. Khung dữ liệu. lặp đi lặp lại
  • cục mịch. apply_along_axis
  • cục mịch. véc tơ hóa
  • bản đồ
  • nhanh hơn
  • bóng tối. khung dữ liệu. map_partitions
  • vùng cực. Khung dữ liệu. ứng dụng
  • vector hóa tích hợp cực
  • tê liệt
  • Numba song song
  • Cython
  • Cython song song

Giới thiệu

Động lực

Trọng tâm là lặp qua các hàng của khung dữ liệu Pandas chứa một số dữ liệu số. Tất cả các phần tử của khung dữ liệu thuộc kiểu dữ liệu

from itertools import cycle
from time import perf_counter

import cython
import dask.dataframe as dd
from numba import jit, float64, njit, prange
import numpy as np
import perfplot
import pandas as pd
import polars as pl
import swifter

%load_ext Cython
%load_ext line_profiler

SD = 124  # random seed
rng = np.random.default_rng[SD]  # random number generator
13. Một hàm được áp dụng cho mỗi hàng, lấy các phần tử của hàng làm đầu vào, làm đối số vô hướng riêng biệt, dưới dạng một mảng hoặc dưới dạng Chuỗi Pandas. Tính toán trả về một giá trị vô hướng trên mỗi hàng, để quá trình cuối cùng trả về một chuỗi Pandas số có cùng chỉ mục với khung dữ liệu gốc. Đối với bài đăng này, một hàm đồ chơi tính toán định thức của ma trận thực đối xứng 3 nhân 3 được sử dụng

$$\begin{equation*} M = \begin{pmatrix} m_{1,1} & m_{1,2} & m_{1,3} \\\ m_{1,2} & m_{2,2

$$. M. = m_{1,1} [m_{2,2} , m_{3,3} - m_{2,3}^2] + m_{1,2} , [2 , m_{2,3} , m_

Đây là một triển khai python thuần túy của hàm thông minh hàng

def det_sym33[m11, m12, m13, m22, m23, m33]:
    """Compute the determinant of a real symmetric 3x3 matrix 
    given its 6 upper triangular coefficients.
    """
    return [
        m11 * [m22 * m33 - m23**2]
        + m12 * [2.0 * m23 * m13 - m12 * m33]
        - m22 * m13**2
    ]

nhập khẩu

from itertools import cycle
from time import perf_counter

import cython
import dask.dataframe as dd
from numba import jit, float64, njit, prange
import numpy as np
import perfplot
import pandas as pd
import polars as pl
import swifter

%load_ext Cython
%load_ext line_profiler

SD = 124  # random seed
rng = np.random.default_rng[SD]  # random number generator

Python version       : 3.9.10
IPython version      : 8.0.1
polars    : 0.12.19
numpy     : 1.21.5
swifter   : 1.0.9
pandas    : 1.4.1
cython    : 0.29.28
numba     : 0.55.1
perfplot  : 0.10.1
dask      : 2022.2.1

Tính toán được thực hiện trên máy tính xách tay có CPU Intel i7-7700HQ 8 nhân @ 2. 80GHz, chạy Linux

chức năng hẹn giờ

Hàm này đang trả về thời gian trôi qua tốt nhất trong _______ 14 thử nghiệm và kết quả tính toán

def timing[func, df, r=10]:
    timings = []
    for i in range[r]:
        start = perf_counter[]
        s = func[df]
        end = perf_counter[]
        elapsed_time = end - start
        timings.append[elapsed_time]
    return s, np.amin[timings]

Tạo một khung dữ liệu với số float ngẫu nhiên

Chúng tôi bắt đầu bằng cách tạo một khung dữ liệu cỡ trung bình để thực hiện so sánh đầu tiên. Sau này chúng tôi sẽ so sánh các phương pháp hiệu quả nhất với các khung dữ liệu dài hơn

________số 8_______

CPU times: user 10.2 ms, sys: 143 µs, total: 10.4 ms
Wall time: 7.99 ms

df.head[3]

m11m12m13m22m23m3300. 7852530. 7858590. 9691360. 7480600. 6555510. 93888510. 1786140. 5886470. 4427990. 3488470. 3309290. 15936920. 9894630. 2571110. 7157650. 5058850. 6641110. 702342

Các hàm theo hàng

Bây giờ chúng ta tạo 3 hàm thông minh theo hàng khác nhau, với các loại đối số khác nhau cho các giá trị hàng đầu vào

  • đối số vô hướng riêng biệt
  • một mảng
  • một loạt gấu trúc

def det_sym33_scalars[m11, m12, m13, m22, m23, m33]:
    return [
        m11 * [m22 * m33 - m23**2]
        + m12 * [2.0 * m23 * m13 - m12 * m33]
        - m22 * m13**2
    ]

def det_sym33_array[m]:
    return [
        m[0] * [m[3] * m[5] - m[4] ** 2]
        + m[1] * [2.0 * m[4] * m[2] - m[1] * m[5]]
        - m[3] * m[2] ** 2
    ]

def det_sym33_series[s]:
    return [
        s.m11 * [s.m22 * s.m33 - s.m23**2]
        + s.m12 * [2.0 * s.m23 * s.m13 - s.m12 * s.m33]
        - s.m22 * s.m13**2
    ]

Trong phần sau đây, chúng tôi có thể thử một số hàm thông minh theo hàng này cho một phương thức lặp khung dữ liệu nhất định, tùy thuộc vào cách phương thức trả về các hàng khung dữ liệu

Pandas tích hợp vector hóa

Trước tiên, chúng ta sẽ sử dụng các hoạt động vector hóa tích hợp từ Pandas. Trong trường hợp hiện tại, việc tính toán theo hàng đơn giản và có thể được thực hiện với các hàm phổ quát cơ bản được áp dụng cho toàn bộ cột. Điều này không sử dụng bất kỳ chức năng theo hàng nào, nhưng cho phép chúng tôi có thời gian tham chiếu

from itertools import cycle
from time import perf_counter

import cython
import dask.dataframe as dd
from numba import jit, float64, njit, prange
import numpy as np
import perfplot
import pandas as pd
import polars as pl
import swifter

%load_ext Cython
%load_ext line_profiler

SD = 124  # random seed
rng = np.random.default_rng[SD]  # random number generator
0

Chúng tôi lưu trữ Sê-ri Pandas kết quả vào biến

from itertools import cycle
from time import perf_counter

import cython
import dask.dataframe as dd
from numba import jit, float64, njit, prange
import numpy as np
import perfplot
import pandas as pd
import polars as pl
import swifter

%load_ext Cython
%load_ext line_profiler

SD = 124  # random seed
rng = np.random.default_rng[SD]  # random number generator
15, để kiểm tra xem các tính toán sau này có dẫn đến kết quả tương tự không

from itertools import cycle
from time import perf_counter

import cython
import dask.dataframe as dd
from numba import jit, float64, njit, prange
import numpy as np
import perfplot
import pandas as pd
import polars as pl
import swifter

%load_ext Cython
%load_ext line_profiler

SD = 124  # random seed
rng = np.random.default_rng[SD]  # random number generator
1

from itertools import cycle
from time import perf_counter

import cython
import dask.dataframe as dd
from numba import jit, float64, njit, prange
import numpy as np
import perfplot
import pandas as pd
import polars as pl
import swifter

%load_ext Cython
%load_ext line_profiler

SD = 124  # random seed
rng = np.random.default_rng[SD]  # random number generator
2

gấu trúc. Khung dữ liệu. lặp đi lặp lại

Chúng tôi biết rằng phương pháp

from itertools import cycle
from time import perf_counter

import cython
import dask.dataframe as dd
from numba import jit, float64, njit, prange
import numpy as np
import perfplot
import pandas as pd
import polars as pl
import swifter

%load_ext Cython
%load_ext line_profiler

SD = 124  # random seed
rng = np.random.default_rng[SD]  # random number generator
16 hơi chậm [ví dụ xem bài viết trước]. Nó lặp qua các hàng của khung dữ liệu dưới dạng các cặp [chỉ mục, Sê-ri]. Ở đây, chúng ta sẽ so sánh 3 loại đối số khác nhau của hàm thông minh theo hàng, với điều kiện là hàng được trả về bởi
from itertools import cycle
from time import perf_counter

import cython
import dask.dataframe as dd
from numba import jit, float64, njit, prange
import numpy as np
import perfplot
import pandas as pd
import polars as pl
import swifter

%load_ext Cython
%load_ext line_profiler

SD = 124  # random seed
rng = np.random.default_rng[SD]  # random number generator
16 là Chuỗi Pandas

  • giá trị vô hướng
  • một mảng Numpy
  • một loạt gấu trúc
tên hàmphương pháp trả lại hàng asrow-wise functionargument typeiterrows_scalarspd. Khung dữ liệu. iterrowspd. Seriesdf_iterrows_scalarsfloat64iterrows_arraypd. Khung dữ liệu. iterrowspd. Seriesdf_iterrows_arrayarrayiterrows_seriespd. Khung dữ liệu. iterrowspd. Seriesdf_iterrows_seriespd. Loạt

đối số vô hướng

from itertools import cycle
from time import perf_counter

import cython
import dask.dataframe as dd
from numba import jit, float64, njit, prange
import numpy as np
import perfplot
import pandas as pd
import polars as pl
import swifter

%load_ext Cython
%load_ext line_profiler

SD = 124  # random seed
rng = np.random.default_rng[SD]  # random number generator
3

from itertools import cycle
from time import perf_counter

import cython
import dask.dataframe as dd
from numba import jit, float64, njit, prange
import numpy as np
import perfplot
import pandas as pd
import polars as pl
import swifter

%load_ext Cython
%load_ext line_profiler

SD = 124  # random seed
rng = np.random.default_rng[SD]  # random number generator
4

from itertools import cycle
from time import perf_counter

import cython
import dask.dataframe as dd
from numba import jit, float64, njit, prange
import numpy as np
import perfplot
import pandas as pd
import polars as pl
import swifter

%load_ext Cython
%load_ext line_profiler

SD = 124  # random seed
rng = np.random.default_rng[SD]  # random number generator
5

from itertools import cycle
from time import perf_counter

import cython
import dask.dataframe as dd
from numba import jit, float64, njit, prange
import numpy as np
import perfplot
import pandas as pd
import polars as pl
import swifter

%load_ext Cython
%load_ext line_profiler

SD = 124  # random seed
rng = np.random.default_rng[SD]  # random number generator
6

cục mịch. đối số ndarray

from itertools import cycle
from time import perf_counter

import cython
import dask.dataframe as dd
from numba import jit, float64, njit, prange
import numpy as np
import perfplot
import pandas as pd
import polars as pl
import swifter

%load_ext Cython
%load_ext line_profiler

SD = 124  # random seed
rng = np.random.default_rng[SD]  # random number generator
7

from itertools import cycle
from time import perf_counter

import cython
import dask.dataframe as dd
from numba import jit, float64, njit, prange
import numpy as np
import perfplot
import pandas as pd
import polars as pl
import swifter

%load_ext Cython
%load_ext line_profiler

SD = 124  # random seed
rng = np.random.default_rng[SD]  # random number generator
8

from itertools import cycle
from time import perf_counter

import cython
import dask.dataframe as dd
from numba import jit, float64, njit, prange
import numpy as np
import perfplot
import pandas as pd
import polars as pl
import swifter

%load_ext Cython
%load_ext line_profiler

SD = 124  # random seed
rng = np.random.default_rng[SD]  # random number generator
9

from itertools import cycle
from time import perf_counter

import cython
import dask.dataframe as dd
from numba import jit, float64, njit, prange
import numpy as np
import perfplot
import pandas as pd
import polars as pl
import swifter

%load_ext Cython
%load_ext line_profiler

SD = 124  # random seed
rng = np.random.default_rng[SD]  # random number generator
6

gấu trúc. Đối số chuỗi

Python version       : 3.9.10
IPython version      : 8.0.1
polars    : 0.12.19
numpy     : 1.21.5
swifter   : 1.0.9
pandas    : 1.4.1
cython    : 0.29.28
numba     : 0.55.1
perfplot  : 0.10.1
dask      : 2022.2.1
1

Python version       : 3.9.10
IPython version      : 8.0.1
polars    : 0.12.19
numpy     : 1.21.5
swifter   : 1.0.9
pandas    : 1.4.1
cython    : 0.29.28
numba     : 0.55.1
perfplot  : 0.10.1
dask      : 2022.2.1
2

Python version       : 3.9.10
IPython version      : 8.0.1
polars    : 0.12.19
numpy     : 1.21.5
swifter   : 1.0.9
pandas    : 1.4.1
cython    : 0.29.28
numba     : 0.55.1
perfplot  : 0.10.1
dask      : 2022.2.1
3

from itertools import cycle
from time import perf_counter

import cython
import dask.dataframe as dd
from numba import jit, float64, njit, prange
import numpy as np
import perfplot
import pandas as pd
import polars as pl
import swifter

%load_ext Cython
%load_ext line_profiler

SD = 124  # random seed
rng = np.random.default_rng[SD]  # random number generator
6

so sánh

Python version       : 3.9.10
IPython version      : 8.0.1
polars    : 0.12.19
numpy     : 1.21.5
swifter   : 1.0.9
pandas    : 1.4.1
cython    : 0.29.28
numba     : 0.55.1
perfplot  : 0.10.1
dask      : 2022.2.1
5

Chúng tôi quan sát thấy rằng bằng cách sử dụng mảng giá trị từ pandas. Sê-ri làm đối số của hàm theo hàng và truy cập dữ liệu bằng các chỉ số là phương pháp nhanh nhất khi sử dụng

from itertools import cycle
from time import perf_counter

import cython
import dask.dataframe as dd
from numba import jit, float64, njit, prange
import numpy as np
import perfplot
import pandas as pd
import polars as pl
import swifter

%load_ext Cython
%load_ext line_profiler

SD = 124  # random seed
rng = np.random.default_rng[SD]  # random number generator
18. Tuy nhiên, cả ba phương pháp
from itertools import cycle
from time import perf_counter

import cython
import dask.dataframe as dd
from numba import jit, float64, njit, prange
import numpy as np
import perfplot
import pandas as pd
import polars as pl
import swifter

%load_ext Cython
%load_ext line_profiler

SD = 124  # random seed
rng = np.random.default_rng[SD]  # random number generator
16 đều rất chậm

gấu trúc. Khung dữ liệu. ứng dụng

Phương thức

from itertools import cycle
from time import perf_counter

import cython
import dask.dataframe as dd
from numba import jit, float64, njit, prange
import numpy as np
import perfplot
import pandas as pd
import polars as pl
import swifter

%load_ext Cython
%load_ext line_profiler

SD = 124  # random seed
rng = np.random.default_rng[SD]  # random number generator
20 cũng lặp lại trên các hàng của khung dữ liệu [với đối số
from itertools import cycle
from time import perf_counter

import cython
import dask.dataframe as dd
from numba import jit, float64, njit, prange
import numpy as np
import perfplot
import pandas as pd
import polars as pl
import swifter

%load_ext Cython
%load_ext line_profiler

SD = 124  # random seed
rng = np.random.default_rng[SD]  # random number generator
21], trả về Sê-ri [mặc định] hoặc một mảng [với
from itertools import cycle
from time import perf_counter

import cython
import dask.dataframe as dd
from numba import jit, float64, njit, prange
import numpy as np
import perfplot
import pandas as pd
import polars as pl
import swifter

%load_ext Cython
%load_ext line_profiler

SD = 124  # random seed
rng = np.random.default_rng[SD]  # random number generator
22]. Đây là những gì tài liệu của Pandas nói về nó

thay vào đó, chức năng được truyền sẽ nhận các đối tượng ndarray. Nếu bạn chỉ áp dụng chức năng giảm NumPy, điều này sẽ đạt được hiệu suất tốt hơn nhiều

tên hàm, phương thức trả về hàng dưới dạng hàm đối số, loại áp dụng_seriespd. Khung dữ liệu. áp dụng. Sê-ridet_sym33_seriespd. Seriesapply_arraypd. Khung dữ liệu. áp dụng. ndarraydet_sym33_arrayarray

gấu trúc. Đối số chuỗi

Python version       : 3.9.10
IPython version      : 8.0.1
polars    : 0.12.19
numpy     : 1.21.5
swifter   : 1.0.9
pandas    : 1.4.1
cython    : 0.29.28
numba     : 0.55.1
perfplot  : 0.10.1
dask      : 2022.2.1
6

Python version       : 3.9.10
IPython version      : 8.0.1
polars    : 0.12.19
numpy     : 1.21.5
swifter   : 1.0.9
pandas    : 1.4.1
cython    : 0.29.28
numba     : 0.55.1
perfplot  : 0.10.1
dask      : 2022.2.1
7

Python version       : 3.9.10
IPython version      : 8.0.1
polars    : 0.12.19
numpy     : 1.21.5
swifter   : 1.0.9
pandas    : 1.4.1
cython    : 0.29.28
numba     : 0.55.1
perfplot  : 0.10.1
dask      : 2022.2.1
8

from itertools import cycle
from time import perf_counter

import cython
import dask.dataframe as dd
from numba import jit, float64, njit, prange
import numpy as np
import perfplot
import pandas as pd
import polars as pl
import swifter

%load_ext Cython
%load_ext line_profiler

SD = 124  # random seed
rng = np.random.default_rng[SD]  # random number generator
6

cục mịch. đối số ndarray

def timing[func, df, r=10]:
    timings = []
    for i in range[r]:
        start = perf_counter[]
        s = func[df]
        end = perf_counter[]
        elapsed_time = end - start
        timings.append[elapsed_time]
    return s, np.amin[timings]
0

def timing[func, df, r=10]:
    timings = []
    for i in range[r]:
        start = perf_counter[]
        s = func[df]
        end = perf_counter[]
        elapsed_time = end - start
        timings.append[elapsed_time]
    return s, np.amin[timings]
1

def timing[func, df, r=10]:
    timings = []
    for i in range[r]:
        start = perf_counter[]
        s = func[df]
        end = perf_counter[]
        elapsed_time = end - start
        timings.append[elapsed_time]
    return s, np.amin[timings]
2

from itertools import cycle
from time import perf_counter

import cython
import dask.dataframe as dd
from numba import jit, float64, njit, prange
import numpy as np
import perfplot
import pandas as pd
import polars as pl
import swifter

%load_ext Cython
%load_ext line_profiler

SD = 124  # random seed
rng = np.random.default_rng[SD]  # random number generator
6

so sánh

def timing[func, df, r=10]:
    timings = []
    for i in range[r]:
        start = perf_counter[]
        s = func[df]
        end = perf_counter[]
        elapsed_time = end - start
        timings.append[elapsed_time]
    return s, np.amin[timings]
4

Thật vậy, sử dụng mảng thay vì Sê-ri nhanh hơn nhiều. Nhưng vẫn chậm hơn rất nhiều so với vector hóa tích hợp sẵn của gấu trúc

gấu trúc. Khung dữ liệu. lặp đi lặp lại

Phương thức

from itertools import cycle
from time import perf_counter

import cython
import dask.dataframe as dd
from numba import jit, float64, njit, prange
import numpy as np
import perfplot
import pandas as pd
import polars as pl
import swifter

%load_ext Cython
%load_ext line_profiler

SD = 124  # random seed
rng = np.random.default_rng[SD]  # random number generator
23 cho phép lặp lại trên các hàng của khung dữ liệu, trả về chúng dưới dạng các bộ được đặt tên. Do đó, các giá trị hàng có thể được truy cập theo tên hoặc theo chỉ mục. Hàm
from itertools import cycle
from time import perf_counter

import cython
import dask.dataframe as dd
from numba import jit, float64, njit, prange
import numpy as np
import perfplot
import pandas as pd
import polars as pl
import swifter

%load_ext Cython
%load_ext line_profiler

SD = 124  # random seed
rng = np.random.default_rng[SD]  # random number generator
24 và
from itertools import cycle
from time import perf_counter

import cython
import dask.dataframe as dd
from numba import jit, float64, njit, prange
import numpy as np
import perfplot
import pandas as pd
import polars as pl
import swifter

%load_ext Cython
%load_ext line_profiler

SD = 124  # random seed
rng = np.random.default_rng[SD]  # random number generator
25 được sử dụng trong trường hợp trước và
from itertools import cycle
from time import perf_counter

import cython
import dask.dataframe as dd
from numba import jit, float64, njit, prange
import numpy as np
import perfplot
import pandas as pd
import polars as pl
import swifter

%load_ext Cython
%load_ext line_profiler

SD = 124  # random seed
rng = np.random.default_rng[SD]  # random number generator
26 trong trường hợp sau

tên hàmphương pháp trả về các hàng như hàm theo chiều dọc đối số typeitertuples_scalarspd. Khung dữ liệu. itertuplesnamedtupledet_sym33_scalarsfloat64itertuples_arraypd. Khung dữ liệu. itertuplesnamedtupledet_sym33_arrayarrayitertuples_seriespd. Khung dữ liệu. itertuplesnamedtupledet_sym33_seriespd. Loạt

đối số vô hướng

def timing[func, df, r=10]:
    timings = []
    for i in range[r]:
        start = perf_counter[]
        s = func[df]
        end = perf_counter[]
        elapsed_time = end - start
        timings.append[elapsed_time]
    return s, np.amin[timings]
5

def timing[func, df, r=10]:
    timings = []
    for i in range[r]:
        start = perf_counter[]
        s = func[df]
        end = perf_counter[]
        elapsed_time = end - start
        timings.append[elapsed_time]
    return s, np.amin[timings]
6

def timing[func, df, r=10]:
    timings = []
    for i in range[r]:
        start = perf_counter[]
        s = func[df]
        end = perf_counter[]
        elapsed_time = end - start
        timings.append[elapsed_time]
    return s, np.amin[timings]
7

from itertools import cycle
from time import perf_counter

import cython
import dask.dataframe as dd
from numba import jit, float64, njit, prange
import numpy as np
import perfplot
import pandas as pd
import polars as pl
import swifter

%load_ext Cython
%load_ext line_profiler

SD = 124  # random seed
rng = np.random.default_rng[SD]  # random number generator
6

cục mịch. đối số mảng

Khi các giá trị hàng được truy cập theo chỉ mục, chúng ta cần tính đến chỉ mục khung dữ liệu, được lập chỉ mục bằng 0

def timing[func, df, r=10]:
    timings = []
    for i in range[r]:
        start = perf_counter[]
        s = func[df]
        end = perf_counter[]
        elapsed_time = end - start
        timings.append[elapsed_time]
    return s, np.amin[timings]
9

%%time
n = 100_000  # dataframe length
column_names = ['m11', 'm12', 'm13', 'm22', 'm23', 'm33']
df = pd.DataFrame[data=rng.random[[n, 6]], columns=column_names]
0

%%time
n = 100_000  # dataframe length
column_names = ['m11', 'm12', 'm13', 'm22', 'm23', 'm33']
df = pd.DataFrame[data=rng.random[[n, 6]], columns=column_names]
1

from itertools import cycle
from time import perf_counter

import cython
import dask.dataframe as dd
from numba import jit, float64, njit, prange
import numpy as np
import perfplot
import pandas as pd
import polars as pl
import swifter

%load_ext Cython
%load_ext line_profiler

SD = 124  # random seed
rng = np.random.default_rng[SD]  # random number generator
6

gấu trúc. Đối số chuỗi

%%time
n = 100_000  # dataframe length
column_names = ['m11', 'm12', 'm13', 'm22', 'm23', 'm33']
df = pd.DataFrame[data=rng.random[[n, 6]], columns=column_names]
3

%%time
n = 100_000  # dataframe length
column_names = ['m11', 'm12', 'm13', 'm22', 'm23', 'm33']
df = pd.DataFrame[data=rng.random[[n, 6]], columns=column_names]
4

%%time
n = 100_000  # dataframe length
column_names = ['m11', 'm12', 'm13', 'm22', 'm23', 'm33']
df = pd.DataFrame[data=rng.random[[n, 6]], columns=column_names]
5

from itertools import cycle
from time import perf_counter

import cython
import dask.dataframe as dd
from numba import jit, float64, njit, prange
import numpy as np
import perfplot
import pandas as pd
import polars as pl
import swifter

%load_ext Cython
%load_ext line_profiler

SD = 124  # random seed
rng = np.random.default_rng[SD]  # random number generator
6

so sánh

%%time
n = 100_000  # dataframe length
column_names = ['m11', 'm12', 'm13', 'm22', 'm23', 'm33']
df = pd.DataFrame[data=rng.random[[n, 6]], columns=column_names]
7

Chúng tôi nhận được loại kết quả tương tự với 3 loại đối số khác nhau. Một lần nữa, chúng ta có thể nói rằng

from itertools import cycle
from time import perf_counter

import cython
import dask.dataframe as dd
from numba import jit, float64, njit, prange
import numpy as np
import perfplot
import pandas as pd
import polars as pl
import swifter

%load_ext Cython
%load_ext line_profiler

SD = 124  # random seed
rng = np.random.default_rng[SD]  # random number generator
23 được ưu tiên hơn
from itertools import cycle
from time import perf_counter

import cython
import dask.dataframe as dd
from numba import jit, float64, njit, prange
import numpy as np
import perfplot
import pandas as pd
import polars as pl
import swifter

%load_ext Cython
%load_ext line_profiler

SD = 124  # random seed
rng = np.random.default_rng[SD]  # random number generator
16 và
from itertools import cycle
from time import perf_counter

import cython
import dask.dataframe as dd
from numba import jit, float64, njit, prange
import numpy as np
import perfplot
import pandas as pd
import polars as pl
import swifter

%load_ext Cython
%load_ext line_profiler

SD = 124  # random seed
rng = np.random.default_rng[SD]  # random number generator
20

cục mịch. apply_along_axis

Hãy thử phương pháp này cho phép áp dụng hàm cho lát cắt 1D dọc theo một trục đã cho [các hàng của mảng 2D trong trường hợp của chúng tôi]

tên hàmphương pháp trả về hàng dưới dạng tham số chức năng theo chiều dọc typenp_apply_along_axisnp. áp dụng_along_axisnp. ndarraydet_sym33_arrayarray

%%time
n = 100_000  # dataframe length
column_names = ['m11', 'm12', 'm13', 'm22', 'm23', 'm33']
df = pd.DataFrame[data=rng.random[[n, 6]], columns=column_names]
8

%%time
n = 100_000  # dataframe length
column_names = ['m11', 'm12', 'm13', 'm22', 'm23', 'm33']
df = pd.DataFrame[data=rng.random[[n, 6]], columns=column_names]
9

CPU times: user 10.2 ms, sys: 143 µs, total: 10.4 ms
Wall time: 7.99 ms
0

from itertools import cycle
from time import perf_counter

import cython
import dask.dataframe as dd
from numba import jit, float64, njit, prange
import numpy as np
import perfplot
import pandas as pd
import polars as pl
import swifter

%load_ext Cython
%load_ext line_profiler

SD = 124  # random seed
rng = np.random.default_rng[SD]  # random number generator
6

Chà, điều này khá chậm và đáng thất vọng

cục mịch. véc tơ hóa

Numpy vectorize đánh giá hàm theo hàng trên từng phần tử của [các] mảng numpy đầu vào. Tuy nhiên, lưu ý cảnh báo trên tài liệu NumPy

Chức năng vectorize được cung cấp chủ yếu để thuận tiện, không phải để thực hiện. Việc thực hiện về cơ bản là một vòng lặp for

tên hàmphương pháp trả về hàng dưới dạng hàm đối số thông minh typenp_vectorize_scalarsnp. vectorizefloat64det_sym33_scalarsfloat64np_vectorize_arraynp. vectorizenp. ndarraydet_sym33_arrayarray

đối số vô hướng

CPU times: user 10.2 ms, sys: 143 µs, total: 10.4 ms
Wall time: 7.99 ms
2

CPU times: user 10.2 ms, sys: 143 µs, total: 10.4 ms
Wall time: 7.99 ms
3

CPU times: user 10.2 ms, sys: 143 µs, total: 10.4 ms
Wall time: 7.99 ms
4

from itertools import cycle
from time import perf_counter

import cython
import dask.dataframe as dd
from numba import jit, float64, njit, prange
import numpy as np
import perfplot
import pandas as pd
import polars as pl
import swifter

%load_ext Cython
%load_ext line_profiler

SD = 124  # random seed
rng = np.random.default_rng[SD]  # random number generator
6

cục mịch. đối số ndarray

Trong trường hợp này, chúng ta cần thêm đối số

from itertools import cycle
from time import perf_counter

import cython
import dask.dataframe as dd
from numba import jit, float64, njit, prange
import numpy as np
import perfplot
import pandas as pd
import polars as pl
import swifter

%load_ext Cython
%load_ext line_profiler

SD = 124  # random seed
rng = np.random.default_rng[SD]  # random number generator
30 để chỉ định hình dạng đầu vào của hàm theo hàng

CPU times: user 10.2 ms, sys: 143 µs, total: 10.4 ms
Wall time: 7.99 ms
6

CPU times: user 10.2 ms, sys: 143 µs, total: 10.4 ms
Wall time: 7.99 ms
7

CPU times: user 10.2 ms, sys: 143 µs, total: 10.4 ms
Wall time: 7.99 ms
8

from itertools import cycle
from time import perf_counter

import cython
import dask.dataframe as dd
from numba import jit, float64, njit, prange
import numpy as np
import perfplot
import pandas as pd
import polars as pl
import swifter

%load_ext Cython
%load_ext line_profiler

SD = 124  # random seed
rng = np.random.default_rng[SD]  # random number generator
6

so sánh

df.head[3]
0

Phiên bản với đối số vô hướng khá thú vị, nhanh hơn

from itertools import cycle
from time import perf_counter

import cython
import dask.dataframe as dd
from numba import jit, float64, njit, prange
import numpy as np
import perfplot
import pandas as pd
import polars as pl
import swifter

%load_ext Cython
%load_ext line_profiler

SD = 124  # random seed
rng = np.random.default_rng[SD]  # random number generator
23

bản đồ

Hãy sử dụng phương pháp Python tiêu chuẩn

from itertools import cycle
from time import perf_counter

import cython
import dask.dataframe as dd
from numba import jit, float64, njit, prange
import numpy as np
import perfplot
import pandas as pd
import polars as pl
import swifter

%load_ext Cython
%load_ext line_profiler

SD = 124  # random seed
rng = np.random.default_rng[SD]  # random number generator
32

tên hàmphương pháp trả về hàng dưới dạng hàm đối số thông minh typemap_scalarsmapfloat64det_sym33_scalarsfloat64

df.head[3]
1

df.head[3]
2

df.head[3]
3

from itertools import cycle
from time import perf_counter

import cython
import dask.dataframe as dd
from numba import jit, float64, njit, prange
import numpy as np
import perfplot
import pandas as pd
import polars as pl
import swifter

%load_ext Cython
%load_ext line_profiler

SD = 124  # random seed
rng = np.random.default_rng[SD]  # random number generator
6

Hiệu suất có vẻ giống nhau giữa

from itertools import cycle
from time import perf_counter

import cython
import dask.dataframe as dd
from numba import jit, float64, njit, prange
import numpy as np
import perfplot
import pandas as pd
import polars as pl
import swifter

%load_ext Cython
%load_ext line_profiler

SD = 124  # random seed
rng = np.random.default_rng[SD]  # random number generator
33 và
from itertools import cycle
from time import perf_counter

import cython
import dask.dataframe as dd
from numba import jit, float64, njit, prange
import numpy as np
import perfplot
import pandas as pd
import polars as pl
import swifter

%load_ext Cython
%load_ext line_profiler

SD = 124  # random seed
rng = np.random.default_rng[SD]  # random number generator
34

nhanh hơn

Swifter là một "gói áp dụng hiệu quả bất kỳ chức năng nào cho chuỗi hoặc khung dữ liệu gấu trúc theo cách nhanh nhất hiện có". chúng tôi sử dụng đối số

from itertools import cycle
from time import perf_counter

import cython
import dask.dataframe as dd
from numba import jit, float64, njit, prange
import numpy as np
import perfplot
import pandas as pd
import polars as pl
import swifter

%load_ext Cython
%load_ext line_profiler

SD = 124  # random seed
rng = np.random.default_rng[SD]  # random number generator
22. Đây là một trích dẫn từ các tài liệu

thô. bool, mặc định Sai
Sai. chuyển từng hàng hoặc cột dưới dạng Sê-ri cho hàm
Thật. thay vào đó, chức năng được truyền sẽ nhận các đối tượng ndarray. Nếu bạn chỉ áp dụng chức năng giảm NumPy, điều này sẽ đạt được hiệu suất tốt hơn nhiều

tên hàmphương pháp trả về các hàng như hàm theo chiều dọccác loại đối sốwifter_applyswifter. áp dụng. ndarraydet_sym33_arrayarray

df.head[3]
5

df.head[3]
6

df.head[3]
7

from itertools import cycle
from time import perf_counter

import cython
import dask.dataframe as dd
from numba import jit, float64, njit, prange
import numpy as np
import perfplot
import pandas as pd
import polars as pl
import swifter

%load_ext Cython
%load_ext line_profiler

SD = 124  # random seed
rng = np.random.default_rng[SD]  # random number generator
6

Quá trình tính toán khá chậm, có lẽ chúng tôi đang thiếu thứ gì đó ở đây và không sử dụng đúng gói này?

bóng tối. khung dữ liệu. map_partitions

Chúng tôi đã cố gắng sử dụng thư viện dask tuyệt vời với phương pháp

from itertools import cycle
from time import perf_counter

import cython
import dask.dataframe as dd
from numba import jit, float64, njit, prange
import numpy as np
import perfplot
import pandas as pd
import polars as pl
import swifter

%load_ext Cython
%load_ext line_profiler

SD = 124  # random seed
rng = np.random.default_rng[SD]  # random number generator
36. Thật không may, chúng tôi đã không hoàn toàn tìm ra cách xử lý đối số
from itertools import cycle
from time import perf_counter

import cython
import dask.dataframe as dd
from numba import jit, float64, njit, prange
import numpy as np
import perfplot
import pandas as pd
import polars as pl
import swifter

%load_ext Cython
%load_ext line_profiler

SD = 124  # random seed
rng = np.random.default_rng[SD]  # random number generator
37. Đây là mô tả từ tài liệu

meta. pd. Khung dữ liệu, pd. Chuỗi, dict, iterable, tuple, tùy chọn Một pd trống. Khung dữ liệu hoặc pd. Chuỗi phù hợp với dtypes và tên cột của đầu ra. Siêu dữ liệu này là cần thiết để nhiều thuật toán trong khung dữ liệu dask hoạt động. Để dễ sử dụng, một số đầu vào thay thế cũng có sẵn. Thay vì một DataFrame, một lệnh của {name. dtype} hoặc có thể lặp lại [name, dtype] có thể được cung cấp [lưu ý rằng thứ tự của các tên phải khớp với thứ tự của các cột]. Thay vì một chuỗi, có thể sử dụng một bộ [tên, dtype]. Nếu không được cung cấp, dask sẽ cố suy luận siêu dữ liệu. Điều này có thể dẫn đến kết quả không mong muốn, vì vậy nên cung cấp meta. Để biết thêm thông tin, xem dask. khung dữ liệu. đồ dùng. make_meta

Việc triển khai sau đây không hoạt động nhưng có thể có nhiều cách hiệu quả hơn để thực hiện

tên hàmphương pháp trả về hàng dưới dạng hàm đối số thông minh typedask_df_map_partitionsdd. map_partitionspd. Sê-ridet_sym33_seriespd. Loạt

df.head[3]
9

def det_sym33_scalars[m11, m12, m13, m22, m23, m33]:
    return [
        m11 * [m22 * m33 - m23**2]
        + m12 * [2.0 * m23 * m13 - m12 * m33]
        - m22 * m13**2
    ]
0

def det_sym33_scalars[m11, m12, m13, m22, m23, m33]:
    return [
        m11 * [m22 * m33 - m23**2]
        + m12 * [2.0 * m23 * m13 - m12 * m33]
        - m22 * m13**2
    ]
1

from itertools import cycle
from time import perf_counter

import cython
import dask.dataframe as dd
from numba import jit, float64, njit, prange
import numpy as np
import perfplot
import pandas as pd
import polars as pl
import swifter

%load_ext Cython
%load_ext line_profiler

SD = 124  # random seed
rng = np.random.default_rng[SD]  # random number generator
6

Không quá tệ nhưng vẫn chậm hơn so với vector hóa tích hợp Pandas. Đây là những gì có thể được tìm thấy trên tài liệu dask

Lưu ý rằng, mặc dù song song, Dask. khung dữ liệu có thể không phải lúc nào cũng nhanh hơn Pandas. Chúng tôi khuyên bạn nên ở lại với Pandas càng lâu càng tốt trước khi chuyển sang Dask. khung dữ liệu

Ngoài ra, chúng tôi đoán rằng có thể có một bản sao khung dữ liệu từ Pandas sang Dask?

vùng cực. Khung dữ liệu. ứng dụng

Polars là một thư viện DataFrame đa luồng nhanh được viết bằng Rust nhưng cũng có sẵn bằng Python và Node. js. Ở đây chúng tôi sẽ sử dụng

from itertools import cycle
from time import perf_counter

import cython
import dask.dataframe as dd
from numba import jit, float64, njit, prange
import numpy as np
import perfplot
import pandas as pd
import polars as pl
import swifter

%load_ext Cython
%load_ext line_profiler

SD = 124  # random seed
rng = np.random.default_rng[SD]  # random number generator
38 cho phép áp dụng chức năng tùy chỉnh trên các hàng của Khung dữ liệu Polars. Các hàng được truyền dưới dạng Tuple. Tuy nhiên, hãy lưu ý cảnh báo này từ tài liệu của Polars

Hãy coi chừng, điều này là chậm

tên hàmphương pháp trả về các hàng như hàm đối số kiểu phân cực_applypolars. Khung dữ liệu. áp dụng [] tupledet_sym33_arrayarray

def det_sym33_scalars[m11, m12, m13, m22, m23, m33]:
    return [
        m11 * [m22 * m33 - m23**2]
        + m12 * [2.0 * m23 * m13 - m12 * m33]
        - m22 * m13**2
    ]
3

def det_sym33_scalars[m11, m12, m13, m22, m23, m33]:
    return [
        m11 * [m22 * m33 - m23**2]
        + m12 * [2.0 * m23 * m13 - m12 * m33]
        - m22 * m13**2
    ]
4

def det_sym33_scalars[m11, m12, m13, m22, m23, m33]:
    return [
        m11 * [m22 * m33 - m23**2]
        + m12 * [2.0 * m23 * m13 - m12 * m33]
        - m22 * m13**2
    ]
5

from itertools import cycle
from time import perf_counter

import cython
import dask.dataframe as dd
from numba import jit, float64, njit, prange
import numpy as np
import perfplot
import pandas as pd
import polars as pl
import swifter

%load_ext Cython
%load_ext line_profiler

SD = 124  # random seed
rng = np.random.default_rng[SD]  # random number generator
6

Điều này không quá tệ nhưng người ta có thể tự hỏi liệu phần lớn thời gian đã trôi qua không được dành để chuyển đổi khung dữ liệu từ Pandas sang Polars và ngược lại. Hãy đo thời gian đã trôi qua trên mỗi dòng bằng trình lược tả dòng

def det_sym33_scalars[m11, m12, m13, m22, m23, m33]:
    return [
        m11 * [m22 * m33 - m23**2]
        + m12 * [2.0 * m23 * m13 - m12 * m33]
        - m22 * m13**2
    ]
7

def det_sym33_scalars[m11, m12, m13, m22, m23, m33]:
    return [
        m11 * [m22 * m33 - m23**2]
        + m12 * [2.0 * m23 * m13 - m12 * m33]
        - m22 * m13**2
    ]
8

Hầu hết thời gian thực sự được sử dụng trong phương pháp

from itertools import cycle
from time import perf_counter

import cython
import dask.dataframe as dd
from numba import jit, float64, njit, prange
import numpy as np
import perfplot
import pandas as pd
import polars as pl
import swifter

%load_ext Cython
%load_ext line_profiler

SD = 124  # random seed
rng = np.random.default_rng[SD]  # random number generator
20. Tuy nhiên, chúng tôi tin rằng có một quy trình sao chép trong bước
from itertools import cycle
from time import perf_counter

import cython
import dask.dataframe as dd
from numba import jit, float64, njit, prange
import numpy as np
import perfplot
import pandas as pd
import polars as pl
import swifter

%load_ext Cython
%load_ext line_profiler

SD = 124  # random seed
rng = np.random.default_rng[SD]  # random number generator
40, điều này sẽ không tối ưu về việc sử dụng bộ nhớ?

Vector hóa các cực

Chúng tôi cũng có thể sử dụng véc tơ tích hợp Polars giống như cách chúng tôi đã làm với Pandas. Điều này không sử dụng các chức năng theo hàng trước đó

def det_sym33_scalars[m11, m12, m13, m22, m23, m33]:
    return [
        m11 * [m22 * m33 - m23**2]
        + m12 * [2.0 * m23 * m13 - m12 * m33]
        - m22 * m13**2
    ]
9

def det_sym33_array[m]:
    return [
        m[0] * [m[3] * m[5] - m[4] ** 2]
        + m[1] * [2.0 * m[4] * m[2] - m[1] * m[5]]
        - m[3] * m[2] ** 2
    ]
0

def det_sym33_array[m]:
    return [
        m[0] * [m[3] * m[5] - m[4] ** 2]
        + m[1] * [2.0 * m[4] * m[2] - m[1] * m[5]]
        - m[3] * m[2] ** 2
    ]
1

from itertools import cycle
from time import perf_counter

import cython
import dask.dataframe as dd
from numba import jit, float64, njit, prange
import numpy as np
import perfplot
import pandas as pd
import polars as pl
import swifter

%load_ext Cython
%load_ext line_profiler

SD = 124  # random seed
rng = np.random.default_rng[SD]  # random number generator
6

Nếu chúng tôi chạy trình cấu hình dòng, chúng tôi có thể quan sát thấy rằng phần lớn thời gian đã trôi qua hiện được dành để chuyển đổi khung dữ liệu giữa Pandas và polars

def det_sym33_array[m]:
    return [
        m[0] * [m[3] * m[5] - m[4] ** 2]
        + m[1] * [2.0 * m[4] * m[2] - m[1] * m[5]]
        - m[3] * m[2] ** 2
    ]
3

def det_sym33_array[m]:
    return [
        m[0] * [m[3] * m[5] - m[4] ** 2]
        + m[1] * [2.0 * m[4] * m[2] - m[1] * m[5]]
        - m[3] * m[2] ** 2
    ]
4

tê liệt

Numba làm cho mã Python nhanh. Ở đây, chúng tôi sử dụng trình trang trí Numba

from itertools import cycle
from time import perf_counter

import cython
import dask.dataframe as dd
from numba import jit, float64, njit, prange
import numpy as np
import perfplot
import pandas as pd
import polars as pl
import swifter

%load_ext Cython
%load_ext line_profiler

SD = 124  # random seed
rng = np.random.default_rng[SD]  # random number generator
41 với
from itertools import cycle
from time import perf_counter

import cython
import dask.dataframe as dd
from numba import jit, float64, njit, prange
import numpy as np
import perfplot
import pandas as pd
import polars as pl
import swifter

%load_ext Cython
%load_ext line_profiler

SD = 124  # random seed
rng = np.random.default_rng[SD]  # random number generator
42 cho chức năng thông minh theo hàng chuyên dụng của Numba. Trong hàm
from itertools import cycle
from time import perf_counter

import cython
import dask.dataframe as dd
from numba import jit, float64, njit, prange
import numpy as np
import perfplot
import pandas as pd
import polars as pl
import swifter

%load_ext Cython
%load_ext line_profiler

SD = 124  # random seed
rng = np.random.default_rng[SD]  # random number generator
43, về cơ bản, chúng tôi triển khai vòng lặp trên các hàng của khung dữ liệu

def det_sym33_array[m]:
    return [
        m[0] * [m[3] * m[5] - m[4] ** 2]
        + m[1] * [2.0 * m[4] * m[2] - m[1] * m[5]]
        - m[3] * m[2] ** 2
    ]
5

def det_sym33_array[m]:
    return [
        m[0] * [m[3] * m[5] - m[4] ** 2]
        + m[1] * [2.0 * m[4] * m[2] - m[1] * m[5]]
        - m[3] * m[2] ** 2
    ]
6

def det_sym33_array[m]:
    return [
        m[0] * [m[3] * m[5] - m[4] ** 2]
        + m[1] * [2.0 * m[4] * m[2] - m[1] * m[5]]
        - m[3] * m[2] ** 2
    ]
7

from itertools import cycle
from time import perf_counter

import cython
import dask.dataframe as dd
from numba import jit, float64, njit, prange
import numpy as np
import perfplot
import pandas as pd
import polars as pl
import swifter

%load_ext Cython
%load_ext line_profiler

SD = 124  # random seed
rng = np.random.default_rng[SD]  # random number generator
6

Vâng, đây là triển khai nhanh nhất cho đến nay

Numba song song

Bây giờ chúng ta sử dụng trình trang trí Numba

from itertools import cycle
from time import perf_counter

import cython
import dask.dataframe as dd
from numba import jit, float64, njit, prange
import numpy as np
import perfplot
import pandas as pd
import polars as pl
import swifter

%load_ext Cython
%load_ext line_profiler

SD = 124  # random seed
rng = np.random.default_rng[SD]  # random number generator
44 cùng với vòng lặp
from itertools import cycle
from time import perf_counter

import cython
import dask.dataframe as dd
from numba import jit, float64, njit, prange
import numpy as np
import perfplot
import pandas as pd
import polars as pl
import swifter

%load_ext Cython
%load_ext line_profiler

SD = 124  # random seed
rng = np.random.default_rng[SD]  # random number generator
45. Theo mặc định, tất cả các lõi có sẵn đều được sử dụng. Hàm thông minh hàng trước
from itertools import cycle
from time import perf_counter

import cython
import dask.dataframe as dd
from numba import jit, float64, njit, prange
import numpy as np
import perfplot
import pandas as pd
import polars as pl
import swifter

%load_ext Cython
%load_ext line_profiler

SD = 124  # random seed
rng = np.random.default_rng[SD]  # random number generator
43 được sử dụng ở đây

def det_sym33_array[m]:
    return [
        m[0] * [m[3] * m[5] - m[4] ** 2]
        + m[1] * [2.0 * m[4] * m[2] - m[1] * m[5]]
        - m[3] * m[2] ** 2
    ]
9

def det_sym33_series[s]:
    return [
        s.m11 * [s.m22 * s.m33 - s.m23**2]
        + s.m12 * [2.0 * s.m23 * s.m13 - s.m12 * s.m33]
        - s.m22 * s.m13**2
    ]
0

def det_sym33_series[s]:
    return [
        s.m11 * [s.m22 * s.m33 - s.m23**2]
        + s.m12 * [2.0 * s.m23 * s.m13 - s.m12 * s.m33]
        - s.m22 * s.m13**2
    ]
1

from itertools import cycle
from time import perf_counter

import cython
import dask.dataframe as dd
from numba import jit, float64, njit, prange
import numpy as np
import perfplot
import pandas as pd
import polars as pl
import swifter

%load_ext Cython
%load_ext line_profiler

SD = 124  # random seed
rng = np.random.default_rng[SD]  # random number generator
6

Phiên bản song song không phải là một cải tiến lớn so với phiên bản Numba tuần tự. Điều này có thể là do kích thước tương đối nhỏ của khung dữ liệu

Cython

Cython là sự pha trộn giữa C và Python. Viết mã Cython liên quan nhiều hơn một chút so với viết Python thuần túy. Lưu ý rằng trong phần sau, chúng tôi đã sử dụng lệnh ma thuật

from itertools import cycle
from time import perf_counter

import cython
import dask.dataframe as dd
from numba import jit, float64, njit, prange
import numpy as np
import perfplot
import pandas as pd
import polars as pl
import swifter

%load_ext Cython
%load_ext line_profiler

SD = 124  # random seed
rng = np.random.default_rng[SD]  # random number generator
47 ở đầu ô sổ ghi chép để biên dịch mã Cython [chúng tôi cũng đã tải phần mở rộng Cython ở đầu sổ ghi chép]

def det_sym33_series[s]:
    return [
        s.m11 * [s.m22 * s.m33 - s.m23**2]
        + s.m12 * [2.0 * s.m23 * s.m13 - s.m12 * s.m33]
        - s.m22 * s.m13**2
    ]
3

def det_sym33_series[s]:
    return [
        s.m11 * [s.m22 * s.m33 - s.m23**2]
        + s.m12 * [2.0 * s.m23 * s.m13 - s.m12 * s.m33]
        - s.m22 * s.m13**2
    ]
4

def det_sym33_series[s]:
    return [
        s.m11 * [s.m22 * s.m33 - s.m23**2]
        + s.m12 * [2.0 * s.m23 * s.m13 - s.m12 * s.m33]
        - s.m22 * s.m13**2
    ]
5

from itertools import cycle
from time import perf_counter

import cython
import dask.dataframe as dd
from numba import jit, float64, njit, prange
import numpy as np
import perfplot
import pandas as pd
import polars as pl
import swifter

%load_ext Cython
%load_ext line_profiler

SD = 124  # random seed
rng = np.random.default_rng[SD]  # random number generator
6

Điều này không nhanh như Numba nhưng gần

Cython song song

Tương tự như những gì chúng ta đã làm với Numba, ở đây chúng ta sử dụng hàm lặp

from itertools import cycle
from time import perf_counter

import cython
import dask.dataframe as dd
from numba import jit, float64, njit, prange
import numpy as np
import perfplot
import pandas as pd
import polars as pl
import swifter

%load_ext Cython
%load_ext line_profiler

SD = 124  # random seed
rng = np.random.default_rng[SD]  # random number generator
45. Đây là một trích dẫn từ các tài liệu

con trăn. song song, tương đông. prange[[start,] stop[, step][, nogil=False][, schedule=None[, chunksize=None]][, num_threads=None]]
Chức năng này có thể được sử dụng cho các vòng lặp song song. OpenMP tự động bắt đầu nhóm luồng và phân phối công việc theo lịch trình được sử dụng. Chủ đề cục bộ và giảm được tự động suy ra cho các biến

def det_sym33_series[s]:
    return [
        s.m11 * [s.m22 * s.m33 - s.m23**2]
        + s.m12 * [2.0 * s.m23 * s.m13 - s.m12 * s.m33]
        - s.m22 * s.m13**2
    ]
7

def det_sym33_series[s]:
    return [
        s.m11 * [s.m22 * s.m33 - s.m23**2]
        + s.m12 * [2.0 * s.m23 * s.m13 - s.m12 * s.m33]
        - s.m22 * s.m13**2
    ]
8

def det_sym33_series[s]:
    return [
        s.m11 * [s.m22 * s.m33 - s.m23**2]
        + s.m12 * [2.0 * s.m23 * s.m13 - s.m12 * s.m33]
        - s.m22 * s.m13**2
    ]
9

Phiên bản song song nhanh hơn một chút so với phiên bản tuần tự nhưng chúng ta nên kiểm tra nó trên các khung dữ liệu lớn hơn

so sánh toàn cầu

Chúng tôi bắt đầu bằng cách so sánh tất cả các phương pháp trên các khung dữ liệu kích thước nhỏ

Khung dữ liệu kích thước nhỏ

from itertools import cycle
from time import perf_counter

import cython
import dask.dataframe as dd
from numba import jit, float64, njit, prange
import numpy as np
import perfplot
import pandas as pd
import polars as pl
import swifter

%load_ext Cython
%load_ext line_profiler

SD = 124  # random seed
rng = np.random.default_rng[SD]  # random number generator
00

from itertools import cycle
from time import perf_counter

import cython
import dask.dataframe as dd
from numba import jit, float64, njit, prange
import numpy as np
import perfplot
import pandas as pd
import polars as pl
import swifter

%load_ext Cython
%load_ext line_profiler

SD = 124  # random seed
rng = np.random.default_rng[SD]  # random number generator
01

from itertools import cycle
from time import perf_counter

import cython
import dask.dataframe as dd
from numba import jit, float64, njit, prange
import numpy as np
import perfplot
import pandas as pd
import polars as pl
import swifter

%load_ext Cython
%load_ext line_profiler

SD = 124  # random seed
rng = np.random.default_rng[SD]  # random number generator
02

Chỉ có các phương thức Numba và Cython là nhanh hơn đáng kể so với vector hóa dựng sẵn của Pandas [

from itertools import cycle
from time import perf_counter

import cython
import dask.dataframe as dd
from numba import jit, float64, njit, prange
import numpy as np
import perfplot
import pandas as pd
import polars as pl
import swifter

%load_ext Cython
%load_ext line_profiler

SD = 124  # random seed
rng = np.random.default_rng[SD]  # random number generator
49]

from itertools import cycle
from time import perf_counter

import cython
import dask.dataframe as dd
from numba import jit, float64, njit, prange
import numpy as np
import perfplot
import pandas as pd
import polars as pl
import swifter

%load_ext Cython
%load_ext line_profiler

SD = 124  # random seed
rng = np.random.default_rng[SD]  # random number generator
03

from itertools import cycle
from time import perf_counter

import cython
import dask.dataframe as dd
from numba import jit, float64, njit, prange
import numpy as np
import perfplot
import pandas as pd
import polars as pl
import swifter

%load_ext Cython
%load_ext line_profiler

SD = 124  # random seed
rng = np.random.default_rng[SD]  # random number generator
04

100010000iterrows_array2. 50e-022. 76e-01swifter_apply4. 08e-034. 41e-02apply_array3. 56e-033. 75e-02np_apply_along_axis2. 79e-033. 71e-02dask_df_map_partitions1. 11e-021. 92e-02itertuples_scalars1. 66e-031. 56e-02poles_apply2. 82e-031. 21e-02map_scalars9. 42e-049. 08e-03np_vectorize_scalars7. 03e-046. 39e-03poles_vectorize2. 39e-032. 30e-03pandas_vectorize1. 50e-031. 52e-03numba_loop_para1. 68e-041. 84e-04cython_loop_para1. 43e-041. 81e-04cython_loop1. 06e-041. 20e-04numba_loop8. 01e-059. 84e-05

Khung dữ liệu kích thước trung bình đến lớn

from itertools import cycle
from time import perf_counter

import cython
import dask.dataframe as dd
from numba import jit, float64, njit, prange
import numpy as np
import perfplot
import pandas as pd
import polars as pl
import swifter

%load_ext Cython
%load_ext line_profiler

SD = 124  # random seed
rng = np.random.default_rng[SD]  # random number generator
05

from itertools import cycle
from time import perf_counter

import cython
import dask.dataframe as dd
from numba import jit, float64, njit, prange
import numpy as np
import perfplot
import pandas as pd
import polars as pl
import swifter

%load_ext Cython
%load_ext line_profiler

SD = 124  # random seed
rng = np.random.default_rng[SD]  # random number generator
02

from itertools import cycle
from time import perf_counter

import cython
import dask.dataframe as dd
from numba import jit, float64, njit, prange
import numpy as np
import perfplot
import pandas as pd
import polars as pl
import swifter

%load_ext Cython
%load_ext line_profiler

SD = 124  # random seed
rng = np.random.default_rng[SD]  # random number generator
04

100000010000000pandas_vectorize3. 95e-024. 10e-01numba_loop3. 92e-037. 33e-02cython_loop4. 40e-035. 29e-02cython_loop_para3. 21e-033. 55e-02numba_loop_para2. 35e-032. 53e-02

Hãy tập trung vào các phương pháp Numba và Cython

from itertools import cycle
from time import perf_counter

import cython
import dask.dataframe as dd
from numba import jit, float64, njit, prange
import numpy as np
import perfplot
import pandas as pd
import polars as pl
import swifter

%load_ext Cython
%load_ext line_profiler

SD = 124  # random seed
rng = np.random.default_rng[SD]  # random number generator
08

from itertools import cycle
from time import perf_counter

import cython
import dask.dataframe as dd
from numba import jit, float64, njit, prange
import numpy as np
import perfplot
import pandas as pd
import polars as pl
import swifter

%load_ext Cython
%load_ext line_profiler

SD = 124  # random seed
rng = np.random.default_rng[SD]  # random number generator
09

from itertools import cycle
from time import perf_counter

import cython
import dask.dataframe as dd
from numba import jit, float64, njit, prange
import numpy as np
import perfplot
import pandas as pd
import polars as pl
import swifter

%load_ext Cython
%load_ext line_profiler

SD = 124  # random seed
rng = np.random.default_rng[SD]  # random number generator
10

Phần kết luận

Pandas tích hợp vector hóa là một giải pháp rất tốt khi có thể. Nếu chúng ta muốn nhanh hơn mà không đau thêm, Numba là giải pháp tốt nhất. Cython nhanh như Numba, linh hoạt, nhưng liên quan nhiều hơn

Chủ Đề