熊猫DataFrame .stack(dropna = False)但保留现有的级别组合

时间:2018-10-02 03:33:46

标签: python python-3.x pandas

我的数据看起来像这样

import numpy as np
import pandas as pd

# My Data
enroll_year = np.arange(2010, 2015)
grad_year = enroll_year + 4
n_students = [[100, 100, 110, 110, np.nan]]

df = pd.DataFrame(
    n_students, 
    columns=pd.MultiIndex.from_arrays(
        [enroll_year, grad_year], 
        names=['enroll_year', 'grad_year']))

print(df)
# enroll_year 2010 2011 2012 2013 2014
# grad_year   2014 2015 2016 2017 2018
# 0            100  100  110  110  NaN

我想做的是堆叠数据,入学年份为一列/索引级别,毕业年份为一列,学生人数为一层,

# enroll_year  grad_year    n
# 2010         2014         100.0
# .            .                .
# .            .                .
# .            .                .
# 2014         2018           NaN

.stack()产生的数据非常接近,但是丢失的记录已删除,

df1 = df.stack(['enroll_year', 'grad_year'])
df1.index = df1.index.droplevel(0)
print(df1)
# enroll_year  grad_year
# 2010         2014         100.0
# 2011         2015         100.0
# 2012         2016         110.0
# 2013         2017         110.0
# dtype: float64

因此,尝试了.stack(dropna=False),但是它将把索引级别扩展到所有入学和毕业年份的组合

df2 = df.stack(['enroll_year', 'grad_year'], dropna=False)
df2.index = df2.index.droplevel(0)
print(df2)
# enroll_year  grad_year
# 2010         2014         100.0
#              2015           NaN
#              2016           NaN
#              2017           NaN
#              2018           NaN
# 2011         2014           NaN
#              2015         100.0
#              2016           NaN
#              2017           NaN
#              2018           NaN
# 2012         2014           NaN
#              2015           NaN
#              2016         110.0
#              2017           NaN
#              2018           NaN
# 2013         2014           NaN
#              2015           NaN
#              2016           NaN
#              2017         110.0
#              2018           NaN
# 2014         2014           NaN
#              2015           NaN
#              2016           NaN
#              2017           NaN
#              2018           NaN
# dtype: float64

我需要对df2进行子集化以获得所需的数据集。

existing_combn = list(zip(
    df.columns.levels[0][df.columns.labels[0]], 
    df.columns.levels[1][df.columns.labels[1]]))

df3 = df2.loc[existing_combn]
print(df3)
# enroll_year  grad_year
# 2010         2014         100.0
# 2011         2015         100.0
# 2012         2016         110.0
# 2013         2017         110.0
# 2014         2018           NaN
# dtype: float64

尽管它只在我的代码中增加了几行,但我想知道是否还有更好,更整洁的方法。

1 个答案:

答案 0 :(得分:1)

unstackpd.DataFrame一起使用,然后将reset_indexdrop不必要的列以及rename的列用作:

pd.DataFrame(df.unstack()).reset_index().drop('level_2',axis=1).rename(columns={0:'n'})

   enroll_year  grad_year      n
0         2010       2014  100.0
1         2011       2015  100.0
2         2012       2016  110.0
3         2013       2017  110.0
4         2014       2018    NaN

或者:

df.unstack().reset_index(level=2, drop=True)
enroll_year  grad_year
2010         2014         100.0
2011         2015         100.0
2012         2016         110.0
2013         2017         110.0
2014         2018           NaN
dtype: float64

或者:

df.unstack().reset_index(level=2, drop=True).reset_index().rename(columns={0:'n'})
   enroll_year  grad_year      n
0         2010       2014  100.0
1         2011       2015  100.0
2         2012       2016  110.0
3         2013       2017  110.0
4         2014       2018    NaN

说明:

print(pd.DataFrame(df.unstack()))
                             0
enroll_year grad_year         
2010        2014      0  100.0
2011        2015      0  100.0
2012        2016      0  110.0
2013        2017      0  110.0
2014        2018      0    NaN

print(pd.DataFrame(df.unstack()).reset_index().drop('level_2',axis=1))
   enroll_year  grad_year      0
0         2010       2014  100.0
1         2011       2015  100.0
2         2012       2016  110.0
3         2013       2017  110.0
4         2014       2018    NaN

print(pd.DataFrame(df.unstack()).reset_index().drop('level_2',axis=1).rename(columns={0:'n'}))
   enroll_year  grad_year      n
0         2010       2014  100.0
1         2011       2015  100.0
2         2012       2016  110.0
3         2013       2017  110.0
4         2014       2018    NaN