2015-02-27 21 views
10

Tôi có một Dataframe với gấu trúc MultiIndex:Làm thế nào để bạn cập nhật các cấp của một gấu trúc MultiIndex sau khi cắt DataFrame của nó?

In [1]: import pandas as pd 
In [2]: multi_index = pd.MultiIndex.from_product([['CAN','USA'],['total']],names=['country','sex']) 
In [3]: df = pd.DataFrame({'pop':[35,318]},index=multi_index) 
In [4]: df 
Out[4]: 
       pop 
country sex 
CAN  total 35 
USA  total 318 

Sau đó, tôi loại bỏ một số hàng từ DataFrame rằng:

In [5]: df = df.query('pop > 100') 

In [6]: df 
Out[6]: 
       pop 
country sex 
USA  total 318 

Nhưng khi tôi tham khảo MutliIndex, nó vẫn có cả hai quốc gia ở mức độ của nó.

In [7]: df.index.levels[0] 
Out[7]: Index([u'CAN', u'USA'], dtype='object') 

tôi có thể khắc phục điều này bản thân mình một cách khá lạ:

In [8]: idx_names = df.index.names 

In [9]: df = df.reset_index(drop=False) 

In [10]: df = df.set_index(idx_names) 

In [11]: df 
Out[11]: 
       pop 
country sex 
USA  total 318 

In [12]: df.index.levels[0] 
Out[12]: Index([u'USA'], dtype='object') 

Nhưng điều này có vẻ khá lộn xộn. Có cách nào tốt hơn tôi đang thiếu?

Trả lời

7

Đây là thứ đã cắn tôi trước đây. Việc bỏ các cột hoặc hàng KHÔNG thay đổi MultiIndex cơ bản, vì lý do hiệu suất và triết học, và điều này chính thức không được coi là lỗi (read more here). Câu trả lời ngắn gọn là các nhà phát triển nói "đó không phải là những gì MultiIndex dành cho". Nếu bạn cần một danh sách các nội dung của một mức MultiIndex sau khi sửa đổi, ví dụ cho lặp hoặc để kiểm tra xem có gì được bao gồm, bạn có thể sử dụng:

df.index.get_level_values(<levelname>) 

này trả về giá trị tích cực hiện nay trong đó mức chỉ số .

Vì vậy, tôi đoán "lừa" ở đây là các API cách tự nhiên để làm điều đó là sử dụng get_level_values ​​thay vì chỉ .index hoặc .columns

+0

Oh và bạn có thể thêm .unique() vào đó nếu bạn không muốn lặp lại. Các giá trị mức mặc định bao gồm mỗi lần xảy ra, do đó bạn sẽ thấy nhiều bản sao trong một kịch bản nhiều chỉ mục điển hình –

+0

Bạn cũng có thể sử dụng 'unique (data.index.values)' để nhận giá trị trên tất cả các cấp. – user2699

0

Tôi sẽ ngạc nhiên nếu có cách "tích hợp" để loại bỏ quốc gia không sử dụng hơn là tạo lại chỉ mục theo cách bạn đang làm (hoặc một số cách tương tự). Nếu bạn nhìn vào chỉ mục của mình trước và sau lát cắt:

In [165]: df.index 
Out[165]: 
MultiIndex(levels=[[u'CAN', u'USA'], [u'total']], 
      labels=[[0, 1], [0, 0]], 
      names=[u'country', u'sex']) 

In [166]: df = df.query('pop > 100') 

In [167]: df.index 
Out[167]: 
MultiIndex(levels=[[u'CAN', u'USA'], [u'total']], 
      labels=[[1], [0]], 
      names=[u'country', u'sex']) 

bạn có thể thấy nhãn - là chỉ mục thành giá trị cấp - đã cập nhật nhưng không phải là giá trị cấp. Đây có thể là một sự tương tự không hoàn hảo, nhưng nó đánh tôi rằng các giá trị mức tương tự với một cột được liệt kê trong một bảng cơ sở dữ liệu, trong khi các nhãn tương tự với các giá trị thực tế của các hàng trong bảng. Nếu bạn xóa tất cả các hàng trong một bảng có giá trị là "CÓ THỂ", nó không thay đổi thực tế là "CÓ THỂ" vẫn là lựa chọn hợp lệ dựa trên định nghĩa cột. Để loại bỏ "CAN" khỏi điều tra, bạn phải thay đổi định nghĩa cột; đây là tương đương với reindexing dataframe trong gấu trúc.

5

Từ phiên bản 0.20.0 sử dụng MultiIndex.remove_unused_levels:

print (df.index) 
MultiIndex(levels=[['CAN', 'USA'], ['total']], 
      labels=[[1], [0]], 
      names=['country', 'sex']) 

df.index = df.index.remove_unused_levels() 

print (df.index) 
MultiIndex(levels=[['USA'], ['total']], 
      labels=[[0], [0]], 
      names=['country', 'sex']) 
Các vấn đề liên quan