Gấu trúc: Làm cách nào tôi có thể sử dụng hàm áp dụng () cho một cột?


257

Tôi có một khung dữ liệu gấu trúc với hai cột. Tôi cần thay đổi các giá trị của cột đầu tiên mà không ảnh hưởng đến cột thứ hai và lấy lại toàn bộ khung dữ liệu chỉ với các giá trị cột đầu tiên được thay đổi. Làm thế nào tôi có thể làm điều đó bằng cách sử dụng áp dụng trong gấu trúc?


4
Xin vui lòng gửi một số dữ liệu mẫu đầu vào và đầu ra mong muốn.
Fabio Lamanna

Bạn gần như không bao giờ nên sử dụng applytrong một tình huống như thế này. Hoạt động trên cột trực tiếp thay thế.
Ted Petrou

Như Ted Petrou đã nói, tránh sử dụng applycàng nhiều càng tốt. Nếu bạn không chắc chắn bạn cần sử dụng nó, có lẽ bạn không nên. Tôi khuyên bạn nên xem khi nào tôi nên sử dụng gấu trúc áp dụng () trong mã của mình? .
cs95

Câu hỏi không hoàn toàn rõ ràng: nó áp dụng một hàm cho mọi phần tử của cột hay áp dụng một hàm cho toàn bộ cột (ví dụ: đảo ngược cột)?
Pierre ALebarÈDE

Câu trả lời:


336

Đưa ra một khung dữ liệu mẫu dflà:

a,b
1,2
2,3
3,4
4,5

những gì bạn muốn là:

df['a'] = df['a'].apply(lambda x: x + 1)

trả về:

   a  b
0  2  2
1  3  3
2  4  4
3  5  5

9
applykhông bao giờ nên được sử dụng trong tình huống như thế này
Ted Petrou

5
@TedPetrou bạn hoàn toàn đúng, đó chỉ là một ví dụ về cách áp dụng một chức năng chung trên một cột duy nhất, như OP yêu cầu.
Fabio Lamanna

14
Khi tôi thử làm điều này, tôi nhận được cảnh báo sau: "Một giá trị đang cố gắng được đặt trên một bản sao của một lát cắt từ DataFrame. Hãy thử sử dụng .loc [row_indexer, col_indexer] = value thay vào đó"
dagrun

24
Như một vấn đề tò mò: tại sao không nên sử dụng trong tình huống đó? Tình hình chính xác là gì?
Chú Ben Ben

19
Nói chung, @UncleBenBen applysử dụng một vòng lặp nội bộ trên các hàng chậm hơn nhiều so với các hàm được vector hóa, ví dụ: df.a = df.a / 2(xem câu trả lời của Mike Muller).
Fabio Lamanna

66

Đối với một cột duy nhất tốt hơn để sử dụng map(), như thế này:

df = pd.DataFrame([{'a': 15, 'b': 15, 'c': 5}, {'a': 20, 'b': 10, 'c': 7}, {'a': 25, 'b': 30, 'c': 9}])

    a   b  c
0  15  15  5
1  20  10  7
2  25  30  9



df['a'] = df['a'].map(lambda a: a / 2.)

      a   b  c
0   7.5  15  5
1  10.0  10  7
2  12.5  30  9

78
Tại sao map()tốt hơn apply()cho một cột duy nhất?
ChaimG

2
Điều này rất hữu ích. Tôi đã sử dụng nó để trích xuất tên tệp từ các đường dẫn được lưu trữ trong một cộtdf['file_name'] = df['Path'].map(lambda a: os.path.basename(a))
mmann1123

46
map () dành cho Sê-ri (tức là các cột đơn) và hoạt động trên một ô tại một thời điểm, trong khi áp dụng () dành cho DataFrame và hoạt động trên toàn bộ một hàng tại một thời điểm.
jpcgt

3
@jpcgt Điều đó có nghĩa là bản đồ nhanh hơn áp dụng trong trường hợp này?
Viragos

@ChaimG tôi thấy hệ điều hành này giải thích rõ: stackoverflow.com/a/19798528/571828

40

Bạn không cần một chức năng nào cả. Bạn có thể làm việc trên toàn bộ một cột trực tiếp.

Dữ liệu ví dụ:

>>> df = pd.DataFrame({'a': [100, 1000], 'b': [200, 2000], 'c': [300, 3000]})
>>> df

      a     b     c
0   100   200   300
1  1000  2000  3000

Một nửa tất cả các giá trị trong cột a:

>>> df.a = df.a / 2
>>> df

     a     b     c
0   50   200   300
1  500  2000  3000

Điều gì xảy ra nếu tôi muốn chia mọi phần tử trong một cột cho "/" và lấy phần đầu tiên?
K47

12

Mặc dù các phản hồi đã cho là chính xác, nhưng chúng sửa đổi khung dữ liệu ban đầu, điều này không phải lúc nào cũng mong muốn (và, được OP yêu cầu ví dụ "sử dụng apply", có thể họ muốn có một phiên bản trả về khung dữ liệu mới, như applyvậy).

Điều này có thể sử dụng assign: nó hợp lệ assignvới các cột hiện có, vì các trạng thái tài liệu (nhấn mạnh là của tôi):

Chỉ định các cột mới cho DataFrame.

Trả về một đối tượng mới với tất cả các cột ban đầu ngoài các cột mới. Các cột hiện có được gán lại sẽ được ghi đè .

Nói ngắn gọn:

In [1]: import pandas as pd

In [2]: df = pd.DataFrame([{'a': 15, 'b': 15, 'c': 5}, {'a': 20, 'b': 10, 'c': 7}, {'a': 25, 'b': 30, 'c': 9}])

In [3]: df.assign(a=lambda df: df.a / 2)
Out[3]: 
      a   b  c
0   7.5  15  5
1  10.0  10  7
2  12.5  30  9

In [4]: df
Out[4]: 
    a   b  c
0  15  15  5
1  20  10  7
2  25  30  9

Lưu ý rằng hàm sẽ được truyền toàn bộ khung dữ liệu, không chỉ cột bạn muốn sửa đổi, vì vậy bạn sẽ cần đảm bảo bạn chọn đúng cột trong lambda của mình.


9

Nếu bạn thực sự lo lắng về tốc độ thực thi của hàm áp dụng và bạn có một bộ dữ liệu khổng lồ để làm việc, bạn có thể sử dụng swifter để thực hiện nhanh hơn, đây là một ví dụ cho swifter trên dataframe:

import pandas as pd
import swifter

def fnc(m):
    return m*3+4

df = pd.DataFrame({"m": [1,2,3,4,5,6], "c": [1,1,1,1,1,1], "x":[5,3,6,2,6,1]})

# apply a self created function to a single column in pandas
df["y"] = df.m.swifter.apply(fnc)

Điều này sẽ cho phép tất cả các lõi CPU của bạn tính toán kết quả do đó nó sẽ nhanh hơn nhiều so với các chức năng áp dụng thông thường. Hãy thử và cho tôi biết nếu nó trở nên hữu ích cho bạn.


1

Hãy để tôi thử một tính toán phức tạp bằng cách sử dụng datetime và xem xét null hoặc khoảng trống. Tôi đang giảm 30 năm trên cột datetime và sử dụng applyphương thức cũng như lambdachuyển đổi định dạng datetime. Line if x != '' else xsẽ chăm sóc tất cả các khoảng trống hoặc null tương ứng.

df['Date'] = df['Date'].fillna('')
df['Date'] = df['Date'].apply(lambda x : ((datetime.datetime.strptime(str(x), '%m/%d/%Y') - datetime.timedelta(days=30*365)).strftime('%Y%m%d')) if x != '' else x)
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.