基于多索引列数据框中的列范围进行切片

Posted

技术标签:

【中文标题】基于多索引列数据框中的列范围进行切片【英文标题】:Slicing based on a range of column in a multiindex column dataframe 【发布时间】:2018-12-03 09:32:40 【问题描述】:

我正在通过执行以下操作来创建我的数据框:

months        = [ 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec' ]
monthyAmounts = [ "actual", "budgeted", "difference" ]

income = []
names  = []

for x in range( incomeIndex + 1, expensesIndex ):
    amounts = [ randint( -1000, 15000 ) for x in range( 0, len( months ) * len( monthyAmounts ) ) ]
    income.append( amounts )
    names.append( f"name_x" )

index    = pd.Index( names, name = 'category' )
columns  = pd.MultiIndex.from_product( [ months, monthyAmounts ], names = [ 'month', 'type' ] )
incomeDF = pd.DataFrame( income, index = index, columns = columns )

数据框如下所示: (删除月份 3 月 - 12 月)

          Jan                            Feb                        ...             
          actual   budgeted   difference actual budgeted difference
name_13   14593     -260      10165      9767     629    10054
name_14    6178     1398      13620      1821   10986     -663
name_15    2432     3279       7545      8196    1052     7386
name_16    9964    13098      10342      5564    4631     7422

我想要的是每一行,将一月到五月的差异列切分。我可以通过以下方式对所有月份的差异列进行切片:

incomeDifferenceDF = incomeDF.loc[ :, idx[ :, 'difference' ] ]

这给了我一个看起来像这样的数据框: (删除了 3 月 - 12 月)

         Jan        Feb          ....
         difference difference                         
name_13       10165      10054  
name_14       13620       -663  
name_15        7545       7386  
name_16       10342       7422  

我试过的是:

incomeDifferenceDF = incomeDF.loc[ :, idx[ 'Jan' : 'May', 'difference' ] ]

但这给了我错误:

UnsortedIndexError: 'MultiIndex slicing requires the index to be lexsorted: slicing on levels [0], lexsort depth 0'

所以,这似乎很接近,但我不确定如何解决这个问题。

我也试过了:

incomeDifferenceDF = incomeDF.loc[ :, idx[ ['Jan':'May'], 'difference' ] ]

但这只会产生错误:

SyntaxError: invalid syntax
( Points at ['Jan':'May'] )

最好的方法是什么?

【问题讨论】:

【参考方案1】:

如果需要通过MultiIndex选择,需要布尔掩码:

index    = pd.Index( [1,2,3,4], name = 'category' )
budgetMonths = pd.date_range( "January, 2018", periods = 12, freq = 'BM' ) 
months        = [ 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 
                  'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec' ]
monthyAmounts = [ "actual", "budgeted", "difference" ]
columns = pd.MultiIndex.from_product( [ months, monthyAmounts ], names = [ 'month', 'type' ])
incomeDF = pd.DataFrame( 10, index = index, columns = columns )

#trick for get values between 
idx = pd.Series(0,index=months).loc['Jan' : 'May'].index
print (idx)
Index(['Jan', 'Feb', 'Mar', 'Apr', 'May'], dtype='object')

mask1 = incomeDF.columns.get_level_values(0).isin(idx)
mask2 = incomeDF.columns.get_level_values(1) == 'difference'

incomeDifferenceDF = incomeDF.loc[:, mask1 & mask2]
print (incomeDifferenceDF)
month           Jan        Feb        Mar        Apr        May
type     difference difference difference difference difference
category                                                       
1                10         10         10         10         10
2                10         10         10         10         10
3                10         10         10         10         10
4                10         10         10         10         10

【讨论】:

hmmm, 1-01-01 不是有效日期,但需要对此进行测试。给我一些时间。 把你需要的所有时间都花在...谢谢...但是,也许,使用特定日期的时间序列和切片已经足够了...但是,能够仍然很好根据月份名称切片(例如 'Jan' : 'May' ) @ericg - 如果值按照新示例中的方式排序,那么您的解决方案运行良好。 @ericg - 嗯,如果想使用月份的名称,选择是有问题的,因为不可能排序。所以可能的解决方案应该是将月份名称更改为数字。 @ericg - 添加了一种可能的解决方案,但很复杂 - 需要布尔掩码。

以上是关于基于多索引列数据框中的列范围进行切片的主要内容,如果未能解决你的问题,请参考以下文章

沿着 pandas 数据框中的列进行高效的跨步切片

如何使用单个索引更新多索引数据框中的记录

如何重新排序 Pandas 中的多索引列?

无法正确组合多索引列(3 级)

根据熊猫数据框中的列标签对数据进行分组

Spark基于其他数据框中的列对数据框中的列进行重复数据删除