2014-04-28 29 views
61

Tôi có một khung dữ liệu gấu trúc trông như thế này (một khá lớn của nó)Cập nhật một dataframe trong gấu trúc trong khi lặp lại từng hàng

  date  exer exp  ifor   mat 
1092 2014-03-17 American M 528.205 2014-04-19 
1093 2014-03-17 American M 528.205 2014-04-19 
1094 2014-03-17 American M 528.205 2014-04-19 
1095 2014-03-17 American M 528.205 2014-04-19  
1096 2014-03-17 American M 528.205 2014-05-17 

bây giờ tôi muốn lặp từng hàng và như tôi đi thông qua mỗi hàng, giá trị của ifor trong mỗi hàng có thể thay đổi tùy thuộc vào một số điều kiện và tôi cần tra cứu một khung dữ liệu khác.

Bây giờ, làm cách nào để cập nhật điều này khi tôi lặp lại. Đã thử một vài điều không ai trong số họ làm việc.

for i, row in df.iterrows(): 
    if <something>: 
     row['ifor'] = x 
    else: 
     row['ifor'] = y 

    df.ix[i]['ifor'] = x 

Không có phương pháp nào trong số này có vẻ hữu hiệu. Tôi không thấy các giá trị được cập nhật trong khung dữ liệu.

+1

Tôi nghĩ rằng bạn muốn 'df.ix [i, 'ifor'] '. 'df.ix [i] ['ifor']' có vấn đề vì nó được lập chỉ mục chuỗi (không đáng tin cậy trong gấu trúc). –

+0

Bạn có thể cung cấp khung hình khác cũng như ''. Liệu mã của bạn có thể được vector hóa hay không sẽ phụ thuộc vào những thứ đó. Nói chung, tránh 'iterrows'. Trong trường hợp của bạn, bạn nên * chắc chắn * tránh nó vì mỗi hàng sẽ là một 'object' dtype' Series'. –

+0

Bạn nên tạo mặt nạ boolean cho điều kiện của mình, cập nhật tất cả các hàng đó rồi đặt phần còn lại thành giá trị khác – EdChum

Trả lời

10

Bạn nên chỉ định giá trị theo df.ix[i, 'exp']=X hoặc df.loc[i, 'exp']=X thay vì df.ix[i]['ifor'] = x.

Nếu không, bạn đang làm việc trên một cái nhìn, và sẽ nhận được một nóng lên:

-c:1: 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

Nhưng chắc chắn, vòng lặp có lẽ tốt hơn nên được thay thế bởi một số thuật toán vectorized để làm cho việc sử dụng đầy đủ các DataFrame như @Phillip Cloud đề xuất.

66

Bạn có thể gán giá trị trong vòng lặp sử dụng df.set_value:

for i, row in df.iterrows(): 
    ifor_val = something 
    if <condition>: 
    ifor_val = something_else 
    df.set_value(i,'ifor',ifor_val) 

nếu bạn không cần các giá trị hàng bạn chỉ có thể lặp qua các chỉ số của df, nhưng tôi giữ bản chính để đối-loop trong trường hợp bạn cần giá trị hàng cho một cái gì đó không được hiển thị ở đây.

+3

Xem http://pandas.pydata.org/pandas-docs/stable/generated/pandas.DataFrame .iterrows.html, dấu đầu dòng thứ hai: "2.Bạn không bao giờ nên sửa đổi một cái gì đó bạn đang lặp qua" –

+13

Tôi không chắc chắn nếu chúng ta đọc nó chính xác như nhau. Nếu bạn nhìn vào mã giả của tôi, tôi thực hiện sửa đổi trên khung dữ liệu, không phải trên giá trị từ trình lặp. Giá trị vòng lặp chỉ được sử dụng cho chỉ mục của giá trị/đối tượng. Điều gì sẽ thất bại là hàng ['ifor'] = some_thing, vì những lý do được đề cập trong tài liệu. – rakke

+1

Cảm ơn bạn đã làm rõ. –

5

Phương pháp bạn có thể sử dụng là itertuples(), nó lặp qua các hàng DataFrame dưới dạng tên tệp, với giá trị chỉ mục làm phần tử đầu tiên của bộ dữ liệu. Và nó nhanh hơn nhiều so với iterrows(). Đối với itertuples(), mỗi row chứa Index trong DataFrame và bạn có thể sử dụng loc để đặt giá trị.

for row in df.itertuples(): 
    if <something>: 
     df.loc[row.Index, 'ifor'] = x 
    else: 
     df.loc[row.Index, 'ifor'] = x 

    df.loc[row.Index, 'ifor'] = x 
2

Đối tượng khung dữ liệu Pandas nên được coi là một chuỗi Series. Nói cách khác, bạn nên nghĩ về nó theo các cột. Lý do tại sao điều này quan trọng là vì khi bạn sử dụng pd.DataFrame.iterrows, bạn đang lặp qua các hàng dưới dạng Chuỗi. Nhưng đây là không phải là Series mà khung dữ liệu đang lưu trữ và do đó chúng là Chuỗi mới được tạo cho bạn trong khi bạn lặp lại. Điều đó ngụ ý rằng khi bạn cố gắng chỉ định tho chúng, các chỉnh sửa đó sẽ không kết thúc được phản ánh trong khung dữ liệu gốc.

Ok, hiện tại điều đó đã hết hạn: Chúng ta phải làm gì?

Gợi ý trước khi bài này bao gồm:

  1. pd.DataFrame.set_valuedeprecated as of Pandas version 0.21
  2. pd.DataFrame.ixdeprecated
  3. pd.DataFrame.loc là tốt nhưng can work on array indexers và bạn có thể làm tốt hơn

Tôi đề nghị.210 Sử dụng pd.DataFrame.at

for i in df.index: 
    if <something>: 
     df.at[i, 'ifor'] = x 
    else: 
     df.at[i, 'ifor'] = y 

Bạn thậm chí có thể thay đổi điều này để:

for i in df.index: 
    df.at[i, 'ifor'] = x if <something> else y 
0
for i, row in df.iterrows(): 
    if <something>: 
     df.at[i, 'ifor'] = x 
    else: 
     df.at[i, 'ifor'] = y 
Các vấn đề liên quan