Python pandas:如果任何列值为 NaN,我如何删除分层索引中的特定级别?

Python pandas: How do I drop specific levels in a hierarchical index if any column values are NaN?

如果某个国家/地区的任何数据值为 NaN,我想在我的层次结构索引中删除整个级别(在本例中为国家/地区)。所以我想从这样的事情开始:

                          M1                   M2
country    year                                   
Arab World 2010           5.240002             NaN
           2009           NaN                  NaN
Bangladesh 2010           6.206065             3.7
           2009           5.708707             NaN
Canada     2010           7.203803             5.8
           2009           6.144833             7.0
Sweden     2010           9.123140             6.0
           2009           5.213283             6.1

像这样:

                          M1                   M2
country    year                                   
Canada     2010           7.203803             5.8
           2009           6.144833             7.0
Sweden     2010           9.123140             6.0
           2009           5.213283             6.1

我已经尝试 df.dropna() 使用 thresh 选项,以及 df.fillna(0) 来尝试使国家/地区的删除更容易,但这两种方法都是为了将​​水平保留在DataFrame 如果 M1 和 M2 包含值,例如2010 年的孟加拉国。

有什么简洁的方法可以解决这个问题吗?

此代码块底部的三行代码完成了繁重的工作,其余部分将您的数据放入 DataFrame(或多或少)。

# get data
data="""
country    year           M1                   M2 
Arab_World 2010           5.240002             NaN
Arab_World 2009           NaN                  NaN
Bangladesh 2010           6.206065             3.7
Bangladesh 2009           5.708707             NaN
Canada     2010           7.203803             5.8
Canada     2009           6.144833             7.0
Sweden     2010           9.123140             6.0
Sweden     2009           5.213283             6.1"""
from StringIO import StringIO # import from io for python 3
df = pd.read_csv(StringIO(data), header=0, index_col=['country', 'year'], sep=r'\s+')

# manipulate rows
to_drop = df.groupby(level='country').apply(lambda x: x.isnull().any().any())
df = df.reset_index(level=0)
keepers = df[(~to_drop[df.country]).tolist()]

产量

In [13]: print(keepers)
     country        M1   M2
year                       
2010  Canada  7.203803  5.8
2009  Canada  6.144833  7.0
2010  Sweden  9.123140  6.0
2009  Sweden  5.213283  6.1

是的,有一种简洁有效的方法可以解决这个问题。 df.dropna() 您走在正确的轨道上,只是您需要 unstack 在应用数据之前。

>>> print df

                       M1   M2
Country    Year               
Arab World 2009       NaN  NaN
           2010  5.240002  NaN
Bangladesh 2009  5.708707  NaN
           2010  6.206065  3.7
Canada     2009  6.144833  7.0
           2010  7.203803  5.8
Sweden     2009  5.213283  6.1
           2010  9.123140  6.0

旋转 DataFrame 使 "Year" 成为最里面的列标签

>>> df1 = df.unstack(level=-1)

删除缺少数据的行

>>> df2 = df1.dropna()  

取消堆叠

>>> print df2.stack()

                    M1   M2
Country Year               
Canada  2009  6.144833  7.0
        2010  7.203803  5.8
Sweden  2009  5.213283  6.1
        2010  9.123140  6.0

将所有这些放在一起:

>>> clean = df.unstack(level=-1).dropna().stack()