Các đường ống chức năng trong python như%>% từ R's magritrr


84

Trong R (thanks to magritrr) bây giờ bạn có thể thực hiện các hoạt động với một cú pháp đường ống chức năng hơn thông qua %>%. Điều này có nghĩa là thay vì viết mã này:

> as.Date("2014-01-01")
> as.character((sqrt(12)^2)

Bạn cũng có thể làm điều này:

> "2014-01-01" %>% as.Date 
> 12 %>% sqrt %>% .^2 %>% as.character

Đối với tôi, điều này dễ đọc hơn và điều này mở rộng cho các trường hợp sử dụng ngoài khung dữ liệu. Ngôn ngữ python có hỗ trợ cho thứ gì đó tương tự không?


1
Câu hỏi tuyệt vời. Tôi đặc biệt quan tâm đến trường hợp, trong đó các hàm có nhiều đối số hơn. Như trong crime_by_state %>% filter(State=="New York", Year==2005) ...phần cuối của How dplyr đã thay thế các thành ngữ R phổ biến nhất của tôi .
Piotr Migdal

1
Tất nhiên, người ta có thể làm điều đó với rất nhiều lambdas, bản đồ và giảm bớt (và làm như vậy rất đơn giản), nhưng tính ngắn gọn và dễ đọc là những điểm chính.
Piotr Migdal

12
Gói được đề cập là magrittr.
piccolbo

1
Đúng vậy, vì lý do tương tự, mọi gói R từng được viết đều do Hadley tạo ra. Anh ấy được biết đến nhiều hơn. (cảnh báo đố kỵ được ngụy trang kém ở đây)
piccolbo

1
Xem câu trả lời cho stackoverflow.com/questions/33658355/… đang giải quyết vấn đề này.
Piotr Migdal

Câu trả lời:


34

Một cách có thể để làm điều này là sử dụng một mô-đun được gọi macropy. Macropy cho phép bạn áp dụng các phép biến đổi cho mã mà bạn đã viết. Do đó a | bcó thể được chuyển đổi thành b(a). Điều này có một số lợi thế và bất lợi.

So với giải pháp được đề cập bởi Sylvain Leroux, Ưu điểm chính là bạn không cần phải tạo các đối tượng infix cho các chức năng bạn quan tâm đến việc sử dụng - chỉ cần đánh dấu các vùng mã mà bạn định sử dụng chuyển đổi. Thứ hai, vì quá trình chuyển đổi được áp dụng tại thời điểm biên dịch, chứ không phải thời gian chạy, mã được chuyển đổi không bị chi phí trong thời gian chạy - tất cả công việc được thực hiện khi mã byte được tạo lần đầu tiên từ mã nguồn.

Những bất lợi chính là macropy yêu cầu một cách nhất định để được kích hoạt để nó hoạt động (sẽ đề cập ở phần sau). Ngược lại với thời gian chạy nhanh hơn, việc phân tích cú pháp mã nguồn phức tạp hơn về mặt tính toán và do đó, chương trình sẽ mất nhiều thời gian hơn để bắt đầu. Cuối cùng, nó thêm một kiểu cú pháp có nghĩa là các lập trình viên không quen thuộc với macropy có thể thấy mã của bạn khó hiểu hơn.

Mã ví dụ:

run.py

import macropy.activate 
# Activates macropy, modules using macropy cannot be imported before this statement
# in the program.
import target
# import the module using macropy

target.py

from fpipe import macros, fpipe
from macropy.quick_lambda import macros, f
# The `from module import macros, ...` must be used for macropy to know which 
# macros it should apply to your code.
# Here two macros have been imported `fpipe`, which does what you want
# and `f` which provides a quicker way to write lambdas.

from math import sqrt

# Using the fpipe macro in a single expression.
# The code between the square braces is interpreted as - str(sqrt(12))
print fpipe[12 | sqrt | str] # prints 3.46410161514

# using a decorator
# All code within the function is examined for `x | y` constructs.
x = 1 # global variable
@fpipe
def sum_range_then_square():
    "expected value (1 + 2 + 3)**2 -> 36"
    y = 4 # local variable
    return range(x, y) | sum | f[_**2]
    # `f[_**2]` is macropy syntax for -- `lambda x: x**2`, which would also work here

print sum_range_then_square() # prints 36

# using a with block.
# same as a decorator, but for limited blocks.
with fpipe:
    print range(4) | sum # prints 6
    print 'a b c' | f[_.split()] # prints ['a', 'b', 'c']

Và cuối cùng là mô-đun thực hiện công việc khó khăn. Tôi đã gọi nó là fpipe cho đường ống chức năng vì cú pháp shell mô phỏng của nó để chuyển đầu ra từ quá trình này sang quá trình khác.

fpipe.py

from macropy.core.macros import *
from macropy.core.quotes import macros, q, ast

macros = Macros()

@macros.decorator
@macros.block
@macros.expr
def fpipe(tree, **kw):

    @Walker
    def pipe_search(tree, stop, **kw):
        """Search code for bitwise or operators and transform `a | b` to `b(a)`."""
        if isinstance(tree, BinOp) and isinstance(tree.op, BitOr):
            operand = tree.left
            function = tree.right
            newtree = q[ast[function](ast[operand])]
            return newtree

    return pipe_search.recurse(tree)

2
Nghe có vẻ tuyệt vời, nhưng như tôi thấy nó chỉ hoạt động trên Python 2.7 (chứ không phải Python 3.4).
Piotr Migdal

3
Tôi đã tạo một thư viện nhỏ hơn không có phần phụ thuộc nào thực hiện tương tự như trình trang trí @fpipe nhưng xác định lại dịch chuyển phải (>>) thay vì hoặc (|): pypi.org/project/pipeop
Robin Hilliard

phản đối vì yêu cầu thư viện của bên thứ 3 với việc sử dụng nhiều trình trang trí là một giải pháp rất phức tạp cho một vấn đề khá đơn giản. Thêm vào đó, nó là một giải pháp duy nhất của python 2. Khá chắc chắn rằng dung dịch trăn vani cũng sẽ nhanh hơn.
jramm

37

Pipes là một tính năng mới trong Pandas 0.16.2 .

Thí dụ:

import pandas as pd
from sklearn.datasets import load_iris

x = load_iris()
x = pd.DataFrame(x.data, columns=x.feature_names)

def remove_units(df):
    df.columns = pd.Index(map(lambda x: x.replace(" (cm)", ""), df.columns))
    return df

def length_times_width(df):
    df['sepal length*width'] = df['sepal length'] * df['sepal width']
    df['petal length*width'] = df['petal length'] * df['petal width']

x.pipe(remove_units).pipe(length_times_width)
x

NB: Phiên bản Pandas vẫn giữ nguyên ngữ nghĩa tham chiếu của Python. Đó là lý do tại sao length_times_widthkhông cần giá trị trả về; nó sửa đổi xtại chỗ.


4
rất tiếc điều này chỉ hoạt động cho khung dữ liệu, vì vậy tôi không thể gán đây là câu trả lời chính xác. nhưng tốt khi đề cập ở đây vì trường hợp sử dụng chính mà tôi đã lưu ý là áp dụng điều này cho các khung dữ liệu.
cantdutchthis

22

PyToolz [doc] cho phép các đường ống có thể ghép tùy ý, chỉ là chúng không được định nghĩa bằng cú pháp toán tử đường ống đó.

Thực hiện theo liên kết trên để bắt đầu nhanh chóng. Và đây là video hướng dẫn: http://pyvideo.org/video/2858/f Chức năng-programming-in-python-with-pytoolz

In [1]: from toolz import pipe

In [2]: from math import sqrt

In [3]: pipe(12, sqrt, str)
Out[3]: '3.4641016151377544'

1
PyToolz là một con trỏ tuyệt vời. Đã nói rằng một liên kết đã chết và liên kết kia sẽ sớm chết
akhmed

2
Các URL cơ sở của anh ấy dường như là: http://matthewrocklin.com/blog và PyToolz toolz.readthedocs.io/en/latest . Ah, sự phù du của internetz ...
smci

18

Ngôn ngữ python có hỗ trợ cho thứ gì đó tương tự không?

"thêm cú pháp đường ống chức năng" đây có thực sự là cú pháp "chức năng" hơn không? Tôi sẽ nói rằng nó thêm cú pháp "infix" vào R.

Điều đó đang được nói, ngữ pháp của Python không hỗ trợ trực tiếp cho ký hiệu infix ngoài các toán tử tiêu chuẩn.


Nếu bạn thực sự cần một cái gì đó như vậy, bạn nên lấy mã đó từ Tomer Filiba làm điểm bắt đầu để triển khai ký hiệu infix của riêng bạn:

Mẫu mã và nhận xét của Tomer Filiba ( http://tomerfiliba.com/blog/Infix-Operators/ ):

from functools import partial

class Infix(object):
    def __init__(self, func):
        self.func = func
    def __or__(self, other):
        return self.func(other)
    def __ror__(self, other):
        return Infix(partial(self.func, other))
    def __call__(self, v1, v2):
        return self.func(v1, v2)

Sử dụng các phiên bản của lớp đặc biệt này, bây giờ chúng ta có thể sử dụng một "cú pháp" mới để gọi các hàm dưới dạng toán tử infix:

>>> @Infix
... def add(x, y):
...     return x + y
...
>>> 5 |add| 6

18

Nếu bạn chỉ muốn điều này cho kịch bản cá nhân, bạn có thể muốn xem xét sử dụng Coconut thay vì Python.

Dừa là một tập hợp của Python. Do đó, bạn có thể sử dụng toán tử ống của Coconut |>, trong khi hoàn toàn bỏ qua phần còn lại của ngôn ngữ Coconut.

Ví dụ:

def addone(x):
    x + 1

3 |> addone

biên dịch thành

# lots of auto-generated header junk

# Compiled Coconut: -----------------------------------------------------------

def addone(x):
    return x + 1

(addone)(3)

print(1 |> isinstance(int))... Lỗi Loại: isinstance dự kiến 2 đối số, có 1
nyanpasu64

1
@ jimbo1qaz Nếu bạn vẫn gặp sự cố này, hãy thử print(1 |> isinstance$(int))hoặc tốt hơn là 1 |> isinstance$(int) |> print.
Solomon Ucko

@Solomon Ucko câu trả lời của bạn là sai. 1 |> print$(2)các cuộc gọi print(2, 1)kể từ khi $ ánh xạ đến các thành phần Python. nhưng tôi muốn print(1, 2)cái nào phù hợp với UFCS và magrittr. Động lực: 1 |> add(2) |> divide(6)nên là 0,5, và tôi không cần dấu ngoặc đơn.
nyanpasu64

@ jimbo1qaz Vâng, có vẻ như nhận xét trước đây của tôi là sai. Bạn thực sự sẽ cần 1 |> isinstance$(?, int) |> print. Đối với các ví dụ khác của bạn: 1 |> print$(?, 2), 1 |> (+)$(?, 2) |> (/)$(?, 6). Tôi không nghĩ rằng bạn có thể tránh dấu ngoặc đơn cho ứng dụng một phần.
Solomon Ucko

Nhìn vào sự xấu xí |>và xấu xí như thế nào (+)$(?, 2), tôi đã đi đến kết luận rằng cơ sở toán học và ngôn ngữ lập trình không muốn tôi sử dụng kiểu cú pháp này, và làm cho nó thậm chí còn xấu hơn việc sử dụng một tập hợp các dấu ngoặc đơn. Tôi sẽ sử dụng nó nếu nó có cú pháp tốt hơn (ví dụ: Dlang có UFCS nhưng IDK về các hàm số học hoặc nếu Python có một ..toán tử ống).
nyanpasu64,

11

dfplymô-đun. Bạn có thể tìm thêm thông tin tại

https://github.com/kieferk/dfply

Một số ví dụ:

from dfply import *
diamonds >> group_by('cut') >> row_slice(5)
diamonds >> distinct(X.color)
diamonds >> filter_by(X.cut == 'Ideal', X.color == 'E', X.table < 55, X.price < 500)
diamonds >> mutate(x_plus_y=X.x + X.y, y_div_z=(X.y / X.z)) >> select(columns_from('x')) >> head(3)

Đây nên được đánh dấu là câu trả lời đúng, theo ý kiến ​​của tôi. Ngoài ra, có vẻ như cả hai dfplydplythonđều là các gói giống nhau. Có sự khác biệt nào giữa chúng không? @BigDataScientist
InfiniteFlash

dfply, dplython, plydataGói là cổng python của dplyrgói để họ sẽ được khá tương tự như trong cú pháp.
BigDataScientist

9

Tôi đã bỏ lỡ |>toán tử ống dẫn từ Elixir vì vậy tôi đã tạo một trình trang trí hàm đơn giản (~ 50 dòng mã) diễn giải lại >>toán tử dịch chuyển phải Python dưới dạng một đường ống giống Elixir tại thời điểm biên dịch bằng cách sử dụng thư viện ast và biên dịch / thực thi:

from pipeop import pipes

def add3(a, b, c):
    return a + b + c

def times(a, b):
    return a * b

@pipes
def calc()
    print 1 >> add3(2, 3) >> times(4)  # prints 24

Tất cả những gì nó đang làm là viết lại a >> b(...)thành b(a, ...).

https://pypi.org/project/pipeop/

https://github.com/robinhilliard/pipes


9

Bạn có thể sử dụng thư viện sspipe . Nó cho thấy hai đối tượng ppx. Tương tự với x %>% f(y,z), bạn có thể viết x | p(f, y, z)và tương tự như x %>% .^2bạn có thể viết x | px**2.

from sspipe import p, px
from math import sqrt

12 | p(sqrt) | px ** 2 | p(str)

8

Xây dựng pipevớiInfix

Như được gợi ý bởi Sylvain Leroux , chúng ta có thể sử dụng Infixtoán tử để tạo một tiền tố pipe. Hãy xem làm thế nào điều này được hoàn thành.

Đầu tiên, đây là mã từ Tomer Filiba

Mẫu mã và nhận xét của Tomer Filiba ( http://tomerfiliba.com/blog/Infix-Operators/ ):

from functools import partial

class Infix(object):
    def __init__(self, func):
        self.func = func
    def __or__(self, other):
        return self.func(other)
    def __ror__(self, other):
        return Infix(partial(self.func, other))
    def __call__(self, v1, v2):
        return self.func(v1, v2)

Sử dụng các phiên bản của lớp đặc biệt này, bây giờ chúng ta có thể sử dụng một "cú pháp" mới để gọi các hàm dưới dạng toán tử infix:

>>> @Infix
... def add(x, y):
...     return x + y
...
>>> 5 |add| 6

Toán tử đường ống truyền đối tượng đứng trước làm đối số cho đối tượng theo sau đường ống, do đó x %>% fcó thể được chuyển đổi thành f(x). Do đó, pipetoán tử có thể được định nghĩa bằng cách sử dụng Infixnhư sau:

In [1]: @Infix
   ...: def pipe(x, f):
   ...:     return f(x)
   ...:
   ...:

In [2]: from math import sqrt

In [3]: 12 |pipe| sqrt |pipe| str
Out[3]: '3.4641016151377544'

Một lưu ý về ứng dụng một phần

Các %>%nhà điều hành từ dpylrlập luận push thông qua đối số đầu tiên trong một chức năng, vì vậy

df %>% 
filter(x >= 2) %>%
mutate(y = 2*x)

tương ứng với

df1 <- filter(df, x >= 2)
df2 <- mutate(df1, y = 2*x)

Cách dễ nhất để đạt được điều gì đó tương tự trong Python là sử dụng currying . Các toolzthư viện cung cấp một currychức năng trang trí mà làm cho xây dựng chức năng cà ri dễ dàng.

In [2]: from toolz import curry

In [3]: from datetime import datetime

In [4]: @curry
    def asDate(format, date_string):
        return datetime.strptime(date_string, format)
    ...:
    ...:

In [5]: "2014-01-01" |pipe| asDate("%Y-%m-%d")
Out[5]: datetime.datetime(2014, 1, 1, 0, 0)

Lưu ý rằng |pipe|đẩy các đối số vào vị trí đối số cuối cùng , đó là

x |pipe| f(2)

tương ứng với

f(2, x)

Khi thiết kế các hàm có sẵn, các đối số tĩnh (tức là các đối số có thể được sử dụng cho nhiều ví dụ) nên được đặt trước đó trong danh sách tham số.

Lưu ý rằng toolzbao gồm nhiều chức năng chuẩn bị trước, bao gồm các chức năng khác nhau từ operatormô-đun.

In [11]: from toolz.curried import map

In [12]: from toolz.curried.operator import add

In [13]: range(5) |pipe| map(add(2)) |pipe| list
Out[13]: [2, 3, 4, 5, 6]

gần tương ứng với điều sau đây trong R

> library(dplyr)
> add2 <- function(x) {x + 2}
> 0:4 %>% sapply(add2)
[1] 2 3 4 5 6

Sử dụng các dấu phân cách infix khác

Bạn có thể thay đổi các ký hiệu bao quanh lời gọi Infix bằng cách ghi đè các phương thức toán tử Python khác. Ví dụ, chuyển đổi __or____ror__để __mod____rmod__sẽ thay đổi |vận hành các modnhà điều hành.

In [5]: 12 %pipe% sqrt %pipe% str
Out[5]: '3.4641016151377544'

6

Thêm 2c của tôi. Cá nhân tôi sử dụng gói fn để lập trình kiểu chức năng. Ví dụ của bạn chuyển thành

from fn import F, _
from math import sqrt

(F(sqrt) >> _**2 >> str)(12)

Flà một lớp trình bao bọc với đường cú pháp kiểu hàm để ứng dụng và cấu tạo từng phần. _là một phương thức khởi tạo kiểu Scala cho các hàm ẩn danh (tương tự như của Python lambda); nó đại diện cho một biến, do đó bạn có thể kết hợp nhiều _đối tượng trong một biểu thức để có được một hàm có nhiều đối số hơn (ví dụ: _ + _tương đương với lambda a, b: a + b). F(sqrt) >> _**2 >> strdẫn đến một Callableđối tượng có thể được sử dụng nhiều lần tùy thích.


Chỉ là những gì tôi đang tìm kiếm - thậm chí đã đề cập đến scala như một hình ảnh minh họa. Đang dùng thử ngay bây giờ
StephenBoesch

@javadba Tôi rất vui vì bạn thấy điều này hữu ích. Hãy lưu ý, điều đó _không linh hoạt 100%: nó không hỗ trợ tất cả các toán tử Python. Thêm vào đó, nếu bạn định sử dụng _trong một phiên tương tác, bạn nên nhập nó dưới một tên khác (ví dụ from fn import _ as var), vì hầu hết (nếu không phải tất cả) các shell tương tác trong Python sử dụng _để đại diện cho giá trị trả về chưa được gán cuối cùng, do đó sẽ che khuất đối tượng được nhập.
Eli Korvigo

5

Không cần thư viện của bên thứ 3 hoặc thủ thuật toán tử khó hiểu để triển khai một hàm ống - bạn có thể tự mình nắm bắt những điều cơ bản khá dễ dàng.

Hãy bắt đầu bằng cách xác định chức năng đường ống thực sự là gì. Về cơ bản, nó chỉ là một cách để thể hiện một loạt các lệnh gọi hàm theo thứ tự logic, chứ không phải là thứ tự tiêu chuẩn 'từ trong ra ngoài'.

Ví dụ, hãy xem các chức năng sau:

def one(value):
  return value

def two(value):
  return 2*value

def three(value):
  return 3*value

Không thú vị lắm, nhưng hãy giả sử những điều thú vị đang xảy ra value. Chúng tôi muốn gọi chúng theo thứ tự, chuyển đầu ra của mỗi cái tiếp theo. Trong trăn vani đó sẽ là:

result = three(two(one(1)))

Nó không thể đọc được và đối với các đường ống phức tạp hơn, nó sẽ trở nên tồi tệ hơn. Vì vậy, đây là một hàm ống đơn giản nhận một đối số ban đầu và một loạt các hàm để áp dụng nó cho:

def pipe(first, *args):
  for fn in args:
    first = fn(first)
  return first

Hãy gọi nó là:

result = pipe(1, one, two, three)

Điều đó trông giống như cú pháp 'đường ống' rất dễ đọc đối với tôi :). Tôi không thấy làm thế nào nó ít dễ đọc hơn bất kỳ toán tử quá tải hoặc bất cứ điều gì tương tự. Trên thực tế, tôi sẽ tranh luận rằng đó là mã python dễ đọc hơn

Đây là đường ống khiêm tốn giải quyết các ví dụ của OP:

from math import sqrt
from datetime import datetime

def as_date(s):
  return datetime.strptime(s, '%Y-%m-%d')

def as_character(value):
  # Do whatever as.character does
  return value

pipe("2014-01-01", as_date)
pipe(12, sqrt, lambda x: x**2, as_character)

3

Một giải pháp thay thế sẽ là sử dụng công cụ dòng công việc dask. Mặc dù nó không thú vị về mặt cú pháp như ...

var
| do this
| then do that

... nó vẫn cho phép biến của bạn chảy xuống chuỗi và sử dụng dask mang lại lợi ích bổ sung của việc song song hóa nếu có thể.

Đây là cách tôi sử dụng dask để thực hiện mô hình chuỗi ống:

import dask

def a(foo):
    return foo + 1
def b(foo):
    return foo / 2
def c(foo,bar):
    return foo + bar

# pattern = 'name_of_behavior': (method_to_call, variables_to_pass_in, variables_can_be_task_names)
workflow = {'a_task':(a,1),
            'b_task':(b,'a_task',),
            'c_task':(c,99,'b_task'),}

#dask.visualize(workflow) #visualization available. 

dask.get(workflow,'c_task')

# returns 100

Sau khi làm việc với elixir, tôi muốn sử dụng mô hình đường ống trong Python. Đây không phải là mẫu hoàn toàn giống nhau, nhưng nó tương tự và như tôi đã nói, đi kèm với các lợi ích bổ sung của song song; nếu bạn yêu cầu dask nhận một nhiệm vụ trong quy trình làm việc của bạn mà không phụ thuộc vào người khác chạy trước, chúng sẽ chạy song song.

Nếu bạn muốn cú pháp dễ dàng hơn, bạn có thể bọc nó trong một thứ gì đó sẽ giúp bạn đặt tên các tác vụ cho bạn. Tất nhiên trong tình huống này, bạn sẽ cần tất cả các hàm lấy đường ống dẫn làm đối số đầu tiên và bạn sẽ mất bất kỳ lợi ích nào của việc ghép song song. Nhưng nếu bạn đồng ý với điều đó, bạn có thể làm điều gì đó như sau:

def dask_pipe(initial_var, functions_args):
    '''
    call the dask_pipe with an init_var, and a list of functions
    workflow, last_task = dask_pipe(initial_var, {function_1:[], function_2:[arg1, arg2]})
    workflow, last_task = dask_pipe(initial_var, [function_1, function_2])
    dask.get(workflow, last_task)
    '''
    workflow = {}
    if isinstance(functions_args, list):
        for ix, function in enumerate(functions_args):
            if ix == 0:
                workflow['task_' + str(ix)] = (function, initial_var)
            else:
                workflow['task_' + str(ix)] = (function, 'task_' + str(ix - 1))
        return workflow, 'task_' + str(ix)
    elif isinstance(functions_args, dict):
        for ix, (function, args) in enumerate(functions_args.items()):
            if ix == 0:
                workflow['task_' + str(ix)] = (function, initial_var)
            else:
                workflow['task_' + str(ix)] = (function, 'task_' + str(ix - 1), *args )
        return workflow, 'task_' + str(ix)

# piped functions
def foo(df):
    return df[['a','b']]
def bar(df, s1, s2):
    return df.columns.tolist() + [s1, s2]
def baz(df):
    return df.columns.tolist()

# setup 
import dask
import pandas as pd
df = pd.DataFrame({'a':[1,2,3],'b':[1,2,3],'c':[1,2,3]})

Bây giờ, với trình bao bọc này, bạn có thể tạo một đường dẫn theo một trong các mẫu cú pháp sau:

# wf, lt = dask_pipe(initial_var, [function_1, function_2])
# wf, lt = dask_pipe(initial_var, {function_1:[], function_2:[arg1, arg2]})

như thế này:

# test 1 - lists for functions only:
workflow, last_task =  dask_pipe(df, [foo, baz])
print(dask.get(workflow, last_task)) # returns ['a','b']

# test 2 - dictionary for args:
workflow, last_task = dask_pipe(df, {foo:[], bar:['string1', 'string2']})
print(dask.get(workflow, last_task)) # returns ['a','b','string1','string2']

một vấn đề với điều này là bạn không thể vượt qua chức năng trong như các đối số :(
VN stack

2

Có một pipemô-đun rất hay ở đây https://pypi.org/project/pipe/ Nó quá tải | vận hành và cung cấp rất nhiều chức năng đường ống như add, first, where, tailv.v.

>>> [1, 2, 3, 4] | where(lambda x: x % 2 == 0) | add
6

>>> sum([1, [2, 3], 4] | traverse)
10

Thêm vào đó, rất dễ dàng để viết các hàm ống dẫn riêng

@Pipe
def p_sqrt(x):
    return sqrt(x)

@Pipe
def p_pr(x):
    print(x)

9 | p_sqrt | p_pr

0

Chức năng đường ống có thể đạt được bằng cách soạn các phương thức gấu trúc với dấu chấm. Đây là một ví dụ dưới đây.

Tải khung dữ liệu mẫu:

import seaborn    
iris = seaborn.load_dataset("iris")
type(iris)
# <class 'pandas.core.frame.DataFrame'>

Minh họa thành phần của các phương pháp gấu trúc với dấu chấm:

(iris.query("species == 'setosa'")
     .sort_values("petal_width")
     .head())

Bạn có thể thêm các phương thức mới vào khung dữ liệu gấu trúc nếu cần ( ví dụ như được thực hiện ở đây ):

pandas.DataFrame.new_method  = new_method
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.