2014-04-08 23 views
5

Tôi có một DataFrame đa giác MultiIndex, trong đó tôi muốn áp dụng một hàm cho một trong các cột của nó và gán kết quả cho cùng một cột đó.Áp dụng một hàm vào cột Đa giác.DataFrame

In [1]: 
    import numpy as np 
    import pandas as pd 
    cols = ['One', 'Two', 'Three', 'Four', 'Five'] 
    df = pd.DataFrame(np.array(list('ABCDEFGHIJKLMNO'), dtype='object').reshape(3,5), index = list('ABC'), columns=cols) 
    df.to_hdf('/tmp/test.h5', 'df') 
    df = pd.read_hdf('/tmp/test.h5', 'df') 
    df 
Out[1]: 
     One  Two  Three Four Five 
    A A  B  C  D  E 
    B F  G  H  I  J 
    C K  L  M  N  O 
    3 rows × 5 columns 

In [2]: 
    df.columns = pd.MultiIndex.from_arrays([list('UUULL'), ['One', 'Two', 'Three', 'Four', 'Five']]) 
    df['L']['Five'] = df['L']['Five'].apply(lambda x: x.lower()) 
    df 
-c:2: SettingWithCopyWarning: A value is trying to be set on a copy of a slice from a DataFrame. 
Try using .loc[row_index,col_indexer] = value instead 
Out[2]: 
     U      L 
     One Two  Three Four Five 
    A A  B  C  D  E 
    B F  G  H  I  J 
    C K  L  M  N  O 
    3 rows × 5 columns 

In [3]: 
    df.columns = ['One', 'Two', 'Three', 'Four', 'Five'] 
    df  
Out[3]: 
     One Two  Three Four Five 
    A A  B  C  D  E 
    B F  G  H  I  J 
    C K  L  M  N  O 
    3 rows × 5 columns 

In [4]: 
    df['Five'] = df['Five'].apply(lambda x: x.upper()) 
    df 
Out[4]: 
     One Two  Three Four Five 
    A A  B  C  D  E 
    B F  G  H  I  J 
    C K  L  M  N  O 
    3 rows × 5 columns 

Như bạn có thể thấy, các chức năng không áp dụng cho các cột, tôi đoán vì tôi nhận được cảnh báo này:

-c:2: SettingWithCopyWarning: A value is trying to be set on a copy of a slice from a DataFrame. 
Try using .loc[row_index,col_indexer] = value instead 

gì là lạ là lỗi này chỉ xảy ra đôi khi, và tôi thiên đường đã không thể hiểu được khi nào nó xảy ra và khi nào thì không.

tôi quản lý để áp dụng các chức năng cắt các dataframe với .loc như cảnh báo đề nghị:

In [5]: 
    df.columns = pd.MultiIndex.from_arrays([list('UUULL'), ['One', 'Two', 'Three', 'Four', 'Five']]) 
    df.loc[:,('L','Five')] = df.loc[:,('L','Five')].apply(lambda x: x.lower()) 
    df 

Out[5]: 
     U      L 
     One Two  Three Four Five 
    A A  B  C  D  e 
    B F  G  H  I  j 
    C K  L  M  N  o 
    3 rows × 5 columns 

nhưng tôi muốn hiểu lý do tại sao hành vi này xảy ra khi thực hiện cắt dict-tương tự (ví dụ df['L']['Five']) và không phải khi sử dụng cắt .loc.

LƯU Ý: Các DataFrame xuất phát từ một tập tin HDF được không multiindexed là thế này có lẽ là nguyên nhân của hành vi kỳ lạ?

EDIT: Tôi đang sử dụng Pandas v.0.13.1NumPy v.1.8.0

Trả lời

5

df['L']['Five'] là chọn mức 0 với giá trị 'L' và trả về một DataFrame, sau đó cột 'Năm' được chọn, trả lại hàng loạt truy cập .

__getitem__ trình truy cập cho một khung dữ liệu ([]), sẽ cố gắng làm điều đúng và cung cấp cho bạn cột đúng. Tuy nhiên, đây là việc lập chỉ mục chuỗi, see here

Để truy cập nhiều chỉ mục, hãy sử dụng ký hiệu tuple, ('a','b').loc rõ ràng, ví dụ: df.loc[:,('a','b')]. Hơn nữa, điều này cho phép lập chỉ mục nhiều trục cùng một lúc (ví dụ: hàng và cột).

Vì vậy, tại sao tính năng này không hoạt động khi bạn lập chỉ mục chuỗi và gán, ví dụ: df['L']['Five'] = value.

df['L'] đặt lại khung dữ liệu được lập chỉ mục đơn lẻ. Sau đó, một hoạt động python khác df_with_L['Five'] chọn chỉ mục chuỗi theo 'Năm' xảy ra. Tôi đã chỉ ra điều này bằng một biến khác. Bởi vì gấu trúc nhìn thấy những hoạt động như các sự kiện riêng biệt (ví dụ như các cuộc gọi riêng biệt để __getitem__, vì vậy nó phải đối xử với họ như hoạt động tuyến tính, chúng xảy ra cái khác.

Contrast này để df.loc[:,('L','Five')] mà vượt qua một tuple lồng nhau của (:,('L','Five')) đến một cuộc gọi duy nhất Điều này cho phép gấu trúc để đối phó với điều này như là một thực thể duy nhất (và fyi khá nhanh hơn một chút bởi vì nó có thể trực tiếp chỉ số vào khung). có thể là một trong hai cuộc gọi có thể trả về một bản sao của dữ liệu do cách nó được cắt. khung gốc. Nó là không thể cho gấu trúc để con số này ra bởi vì họ là 2 hoạt động python riêng biệt mà không được kết nối.

Cảnh báo SettingWithCopy là một 'heuristic' để phát hiện điều này (có nghĩa là nó có xu hướng bắt hầu hết các trường hợp chỉ đơn giản là kiểm tra nhẹ). Nhận ra điều này thật sự là một cách phức tạp.

Các hoạt động .loc là một hoạt động python duy nhất, và do đó có thể chọn một lát (mà vẫn có thể là một bản sao), nhưng cho phép gấu trúc để gán slice đó trở lại vào khung sau khi nó được sửa đổi như vậy, thiết lập các giá trị như bạn sẽ suy nghĩ.

Lý do cảnh báo, là điều này. Đôi khi khi bạn cắt một mảng, bạn sẽ chỉ nhận được một khung nhìn trở lại, điều đó có nghĩa là bạn có thể đặt nó không thành vấn đề. Tuy nhiên, ngay cả một mảng dtyped có thể tạo bản sao nếu được cắt theo một cách cụ thể. Một DataFrame đa dtyped (có nghĩa là nó đã nói float và dữ liệu đối tượng), hầu như luôn luôn mang lại một bản sao. Việc chế độ xem có được tạo hay không phụ thuộc vào bố cục bộ nhớ của mảng.

Lưu ý: điều này không liên quan gì đến nguồn dữ liệu.

+1

Tôi thực sự thực sự thích giải thích này ... Tôi biết chúng tôi có một tài liệu tương tự trong tài liệu, nhưng điều này có văn xuôi tốt hơn. Chúng ta có thể làm một 'pd.merge (orig_doc, this_explanation, how = 'right')'? :) –

+0

được cập nhật: http://pandas-docs.github.io/pandas-docs-travis/indexing.html#returning-a-view-versus-a-copy – Jeff

Các vấn đề liên quan