Python 使用dataframe根据不同级别的键范围从多索引行进行切片的方便方法

Python 使用dataframe根据不同级别的键范围从多索引行进行切片的方便方法,python,pandas,slice,multi-index,Python,Pandas,Slice,Multi Index,我有一个类似这样的多索引数据帧: data = np.random.random((1800,9)) col = pd.MultiIndex.from_product([('A','B','C'),('a','b','c')]) year = range(2006,2011) month = range(1,13) day = range(1,31) idx = pd.MultiIndex.from_product([year,month,day], names=['Year','Month

我有一个类似这样的多索引数据帧:

data = np.random.random((1800,9))
col = pd.MultiIndex.from_product([('A','B','C'),('a','b','c')])

year = range(2006,2011)
month = range(1,13)
day = range(1,31)

idx = pd.MultiIndex.from_product([year,month,day], names=['Year','Month','Day'])

df1 = pd.DataFrame(data, idx, col)
它有多个索引行,分别为
。我希望能够从这个数据帧中选择行,就像它是一个具有DatetimeIndex的数据帧一样

具有DatetimeIndex的等效数据帧为:

idx = pd.DatetimeIndex(start='2006-01-01', end='2010-12-31', freq='d')
timeidx = [ix for ix in idx if ix.day < 29]
df2 = pd.DataFrame(data, timeidx, col)
等于
True


我知道我可以通过
df1.xs('2006',level='Year')
选择横截面,但我基本上需要一种简单的方法来复制为
df2
所做的工作,因为我被迫使用此索引而不是DatetimeIndex。

将它们存储为字符串会立即遇到的一个问题是
'2'>'10'
,这几乎肯定不是您想要的,因此我建议使用ints。即:

year = range(2006,2011)
month = range(1,13)
day = range(1,31)
我认为您应该能够在这里使用pd.indexlice,我的第一个想法是按如下方式使用它:

In [11]: idx = pd.IndexSlice

In [12]: df1.loc[idx[2006:2008, 6:10, 6:11], :]
...
但是这显示了2006年8月至6月10日和6月11日之间的时间(即3*5*6=90天)


这是一种非矢量化方法,只需比较元组:

In [21]: df1.index.map(lambda x: (2006, 6, 6) < x < (2008, 10, 11))
Out[21]: array([False, False, False, ..., False, False, False], dtype=bool)

In [22]: df1[df1.index.map(lambda x: (2006, 6, 6) < x < (2008, 10, 11))]
# just the (844) rows you want

你就不能把其他三种元素合并成一个新的专栏吗?或者这在你的情况下不可行我希望!在我的例子中,我的日期范围从1850年到2300年(DatetimeIndex限制在2263年),并且有不同的日历,如360天和其他变化,因此PeriodIndex也不起作用。这种方法在一些不同的地方被建议作为一种替代方法,但是我需要能够在我的工作中进行类似的索引。哦,我明白你的意思了。是的,这会起作用,但我必须从.csv加载数据,将这三列作为索引,每次保存文件时,都需要将它们放回索引中。也许还有另一种方法足够简单。你能在csv中添加一个完整的日期字段列吗?使用一些简单的命令行可以很容易/快速地做到这一点。通过将这些字符串存储为
'2'>'10'
,您会立即遇到一个问题,这几乎肯定不是您想要的,因此我建议使用ints。我相信有一种方法可以做到这一点。。。但我想不起来了。我猜浮点表示法附带了浮点切片的通常epsilon警告。所以这就是map的工作原理。看起来很有希望,稍后我将不得不在我的桌面上进行测试。
In [21]: df1.index.map(lambda x: (2006, 6, 6) < x < (2008, 10, 11))
Out[21]: array([False, False, False, ..., False, False, False], dtype=bool)

In [22]: df1[df1.index.map(lambda x: (2006, 6, 6) < x < (2008, 10, 11))]
# just the (844) rows you want
In [31]: df1.index.get_level_values(0).values + df1.index.get_level_values(1).values * 1e-3 + df1.index.get_level_values(2).values * 1e-6
Out[31]:
array([ 2006.001001,  2006.001002,  2006.001003, ...,  2010.012028,
        2010.012029,  2010.01203 ])