Python Pandas - 如何在列中展平分层索引

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/14507794/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-18 11:39:35  来源:igfitidea点击:

Pandas - How to flatten a hierarchical index in columns

pythonpandasdataframe

提问by Ross R

I have a data frame with a hierarchical index in axis 1 (columns) (from a groupby.aggoperation):

我在轴 1(列)中有一个带有分层索引的数据框(来自groupby.agg操作):

     USAF   WBAN  year  month  day  s_PC  s_CL  s_CD  s_CNT  tempf       
                                     sum   sum   sum    sum   amax   amin
0  702730  26451  1993      1    1     1     0    12     13  30.92  24.98
1  702730  26451  1993      1    2     0     0    13     13  32.00  24.98
2  702730  26451  1993      1    3     1    10     2     13  23.00   6.98
3  702730  26451  1993      1    4     1     0    12     13  10.04   3.92
4  702730  26451  1993      1    5     3     0    10     13  19.94  10.94

I want to flatten it, so that it looks like this (names aren't critical - I could rename):

我想将它压平,使其看起来像这样(名称并不重要 - 我可以重命名):

     USAF   WBAN  year  month  day  s_PC  s_CL  s_CD  s_CNT  tempf_amax  tmpf_amin   
0  702730  26451  1993      1    1     1     0    12     13  30.92          24.98
1  702730  26451  1993      1    2     0     0    13     13  32.00          24.98
2  702730  26451  1993      1    3     1    10     2     13  23.00          6.98
3  702730  26451  1993      1    4     1     0    12     13  10.04          3.92
4  702730  26451  1993      1    5     3     0    10     13  19.94          10.94

How do I do this? (I've tried a lot, to no avail.)

我该怎么做呢?(我试了很多,都无济于事。)

Per a suggestion, here is the head in dict form

根据建议,这是字典形式的头部

{('USAF', ''): {0: '702730',
  1: '702730',
  2: '702730',
  3: '702730',
  4: '702730'},
 ('WBAN', ''): {0: '26451', 1: '26451', 2: '26451', 3: '26451', 4: '26451'},
 ('day', ''): {0: 1, 1: 2, 2: 3, 3: 4, 4: 5},
 ('month', ''): {0: 1, 1: 1, 2: 1, 3: 1, 4: 1},
 ('s_CD', 'sum'): {0: 12.0, 1: 13.0, 2: 2.0, 3: 12.0, 4: 10.0},
 ('s_CL', 'sum'): {0: 0.0, 1: 0.0, 2: 10.0, 3: 0.0, 4: 0.0},
 ('s_CNT', 'sum'): {0: 13.0, 1: 13.0, 2: 13.0, 3: 13.0, 4: 13.0},
 ('s_PC', 'sum'): {0: 1.0, 1: 0.0, 2: 1.0, 3: 1.0, 4: 3.0},
 ('tempf', 'amax'): {0: 30.920000000000002,
  1: 32.0,
  2: 23.0,
  3: 10.039999999999999,
  4: 19.939999999999998},
 ('tempf', 'amin'): {0: 24.98,
  1: 24.98,
  2: 6.9799999999999969,
  3: 3.9199999999999982,
  4: 10.940000000000001},
 ('year', ''): {0: 1993, 1: 1993, 2: 1993, 3: 1993, 4: 1993}}

采纳答案by Andy Hayden

I think the easiest way to do this would be to set the columns to the top level:

我认为最简单的方法是将列设置为顶级:

df.columns = df.columns.get_level_values(0)

Note: if the to level has a name you can also access it by this, rather than 0.

注意:如果 to 级别有名称,您也可以通过 this 访问它,而不是 0。

.

.

If you want to combine/joinyour MultiIndex into one Index (assuming you have just string entries in your columns)you could:

如果您想将joinMultiIndex组合成一个索引(假设您的列中只有字符串条目),您可以:

df.columns = [' '.join(col).strip() for col in df.columns.values]

Note: we must stripthe whitespace for when there is no second index.

注意:strip当没有第二个索引时,我们必须有空格。

In [11]: [' '.join(col).strip() for col in df.columns.values]
Out[11]: 
['USAF',
 'WBAN',
 'day',
 'month',
 's_CD sum',
 's_CL sum',
 's_CNT sum',
 's_PC sum',
 'tempf amax',
 'tempf amin',
 'year']

回答by Zelazny7

And if you want to retain any of the aggregation info from the second level of the multiindex you can try this:

如果您想保留多索引第二级的任何聚合信息,您可以尝试以下操作:

In [1]: new_cols = [''.join(t) for t in df.columns]
Out[1]:
['USAF',
 'WBAN',
 'day',
 'month',
 's_CDsum',
 's_CLsum',
 's_CNTsum',
 's_PCsum',
 'tempfamax',
 'tempfamin',
 'year']

In [2]: df.columns = new_cols

回答by Theodros Zelleke

Andy Hayden's answer is certainly the easiest way -- if you want to avoid duplicate column labels you need to tweak a bit

安迪海登的答案当然是最简单的方法——如果你想避免重复的列标签,你需要稍微调整一下

In [34]: df
Out[34]: 
     USAF   WBAN  day  month  s_CD  s_CL  s_CNT  s_PC  tempf         year
                               sum   sum    sum   sum   amax   amin      
0  702730  26451    1      1    12     0     13     1  30.92  24.98  1993
1  702730  26451    2      1    13     0     13     0  32.00  24.98  1993
2  702730  26451    3      1     2    10     13     1  23.00   6.98  1993
3  702730  26451    4      1    12     0     13     1  10.04   3.92  1993
4  702730  26451    5      1    10     0     13     3  19.94  10.94  1993


In [35]: mi = df.columns

In [36]: mi
Out[36]: 
MultiIndex
[(USAF, ), (WBAN, ), (day, ), (month, ), (s_CD, sum), (s_CL, sum), (s_CNT, sum), (s_PC, sum), (tempf, amax), (tempf, amin), (year, )]


In [37]: mi.tolist()
Out[37]: 
[('USAF', ''),
 ('WBAN', ''),
 ('day', ''),
 ('month', ''),
 ('s_CD', 'sum'),
 ('s_CL', 'sum'),
 ('s_CNT', 'sum'),
 ('s_PC', 'sum'),
 ('tempf', 'amax'),
 ('tempf', 'amin'),
 ('year', '')]

In [38]: ind = pd.Index([e[0] + e[1] for e in mi.tolist()])

In [39]: ind
Out[39]: Index([USAF, WBAN, day, month, s_CDsum, s_CLsum, s_CNTsum, s_PCsum, tempfamax, tempfamin, year], dtype=object)

In [40]: df.columns = ind




In [46]: df
Out[46]:?
? ? ?USAF ? WBAN ?day ?month ?s_CDsum ?s_CLsum ?s_CNTsum ?s_PCsum ?tempfamax ?tempfamin ?\
0 ?702730 ?26451 ? ?1 ? ? ?1 ? ? ? 12 ? ? ? ?0 ? ? ? ?13 ? ? ? ?1 ? ? ?30.92 ? ? ?24.98 ??
1 ?702730 ?26451 ? ?2 ? ? ?1 ? ? ? 13 ? ? ? ?0 ? ? ? ?13 ? ? ? ?0 ? ? ?32.00 ? ? ?24.98 ??
2 ?702730 ?26451 ? ?3 ? ? ?1 ? ? ? ?2 ? ? ? 10 ? ? ? ?13 ? ? ? ?1 ? ? ?23.00 ? ? ? 6.98 ??
3 ?702730 ?26451 ? ?4 ? ? ?1 ? ? ? 12 ? ? ? ?0 ? ? ? ?13 ? ? ? ?1 ? ? ?10.04 ? ? ? 3.92 ??
4 ?702730 ?26451 ? ?5 ? ? ?1 ? ? ? 10 ? ? ? ?0 ? ? ? ?13 ? ? ? ?3 ? ? ?19.94 ? ? ?10.94 ??




? ?year ?
0 ?1993 ?
1 ?1993 ?
2 ?1993 ?
3 ?1993 ?
4 ?1993

回答by agartland

In case you want to have a separator in the name between levels, this function works well.

如果您想在级别之间的名称中使用分隔符,则此功能效果很好。

def flattenHierarchicalCol(col,sep = '_'):
    if not type(col) is tuple:
        return col
    else:
        new_col = ''
        for leveli,level in enumerate(col):
            if not level == '':
                if not leveli == 0:
                    new_col += sep
                new_col += level
        return new_col

df.columns = df.columns.map(flattenHierarchicalCol)

回答by Gleb Yarnykh

pd.DataFrame(df.to_records()) # multiindex become columns and new index is integers only

回答by Holy cow

You could also do as below. Consider dfto be your dataframe and assume a two level index (as is the case in your example)

你也可以做如下。考虑df作为您的数据框并假设一个两级索引(就像您的示例中的情况一样)

df.columns = [(df.columns[i][0])+'_'+(datadf_pos4.columns[i][1]) for i in range(len(df.columns))]

回答by Niels

A bit late maybe, but if you are not worried about duplicate column names:

可能有点晚了,但如果您不担心重复的列名:

df.columns = df.columns.tolist()

回答by tvt173

df.columns = ['_'.join(tup).rstrip('_') for tup in df.columns.values]

回答by jxstanford

A general solution that handles multiple levels and mixed types:

处理多层次和混合类型的通用解决方案:

df.columns = ['_'.join(tuple(map(str, t))) for t in df.columns.values]

回答by Nolan Conaway

Following @jxstanford and @tvt173, I wrote a quick function which should do the trick, regardless of string/int column names:

在@jxstanford 和@tvt173 之后,我编写了一个快速函数,无论字符串/整数列名如何,它都应该可以解决问题:

def flatten_cols(df):
    df.columns = [
        '_'.join(tuple(map(str, t))).rstrip('_') 
        for t in df.columns.values
        ]
    return df