以1级索引为条件,从多索引数据帧快速删除行

时间:2014-09-26 21:09:15

标签: python pandas

我在从多索引的pandas数据帧快速删除行时遇到问题,其中丢弃标准基于1级索引。或者等效地,通过附加单索引数据帧或numpy数组作为行来构建多索引数据帧。在我的具体例子中,我有一个名为“watch”的数据框,如下所示:

                             userid   watchers
repositoryid         date       
     5910995   1348293168   1449180          1
     5911012   1348292421   2627657          1
     5911046   1367171000   1219404          1
               1368722792   1892225          2
               1383586883   2150178          3
     5911088   1348302179   1521780          1
         ...

其中,repositoryid和date分别是multiindex的级别0和1,userid和watchers是数据列。因此,对于每个repositoryid,我基本上都有一系列用户开始观看存储库的事件。对于每个repositoryid,我也知道来自其他地方的特定创建日期。现在我想删除日期>的所有行creationdate + timewindow,其中timewindow是常量。

我尝试使用drop()函数,但这非常慢。我认为布尔屏蔽将是最好的解决方案,但我无法使其与多索引一起使用。我也尝试过几次尝试从头开始构建一个新的数据框架,最新的一个就是:

watch_new = DataFrame(columns=['date', 'userid', 'watchers'])
for i,rid in enumerate(watch.index.get_level_values('repositoryid')):
    creationdate = repository.loc[rid].date.squeeze()
    thistimeseries = watch.loc[rid]
    thistimeseries = thistimeseries[thistimeseries.index <= creationdate+timewindow]
    thistimeseries.reset_index(inplace=True)
    if len(thistimeseries) != 0:
        watch_new.loc[rid] = thistimeseries.as_matrix()

不幸的是,只要thistimeseries.as_matrix()有多行,我就会收到一条错误消息,例如(在这种情况下,10行):

ValueError: could not broadcast input array from shape (10,3) into shape (3)

所以,我的问题是,1a)如何从多级索引数据帧中快速删除行,条件是1级索引,或等效地1b)如何将单索引数据帧插入多索引数据帧,2)这是解决我问题的最佳=最快的方式,还是应该尝试完全不同的方法?

(我也尝试不使用索引,但这太慢了。我玩加入,合并,分组等等,不幸的是我无法让他们解决我的问题。我花了最近5天学习这本优秀的书籍“Python for Data Analysis”并尝试在线找到这个问题的解决方案,但又没有成功。我希望高级熊猫用户可以为这个看似简单的问题提供优雅的解决方案吗?非常感谢!)

1 个答案:

答案 0 :(得分:0)

从此设置开始:

import pandas as pd
df = pd.read_table('data', sep='\s+').set_index(['repositoryid', 'date'])
repository = pd.read_table('data2', sep='\s+').set_index(['repositoryid'])
timewindow = 100

假设我们有df

                          userid  watchers
repositoryid date                         
5910995      1348293168  1449180         1
5911012      1348292421  2627657         1
5911046      1367171000  1219404         1
             1368722792  1892225         2
             1383586883  2150178         3
5911088      1348302179  1521780         1

repository

                    date
repositoryid            
5910995       1348293200
5911012       1348292400
5911046       1368722800
5911088       1348303000

目前,Pandas不支持仅合并MultiIndex的某些级别。因此,dfrepository必须具有相同的索引形状才能合并:

df.reset_index(level='date', inplace=True)
df = df.join(repository, rsuffix='_threshold')

产量

                    date   userid  watchers  date_threshold
repositoryid                                               
5910995       1348293168  1449180         1      1348293200
5911012       1348292421  2627657         1      1348292400
5911046       1367171000  1219404         1      1368722800
5911046       1368722792  1892225         2      1368722800
5911046       1383586883  2150178         3      1368722800
5911088       1348302179  1521780         1      1348303000

现在您可以将timewindow添加到date_threshold

df['date_threshold'] += timewindow

并在date小于date_threshold

时进行比较
mask = df['date'] < df['date_threshold']

产生类似

的布尔系列
In [207]: mask
Out[207]: 
repositoryid
5910995          True
5911012          True
5911046          True
5911046          True
5911046         False
5911088          True
dtype: bool

使用布尔系列,可以使用df.loc

轻松选择所需的行
In [208]: df.loc[mask]
Out[208]: 
                    date   userid  watchers  date_threshold
repositoryid                                               
5910995       1348293168  1449180         1      1348293300
5911012       1348292421  2627657         1      1348292500
5911046       1367171000  1219404         1      1368722900
5911046       1368722792  1892225         2      1368722900
5911088       1348302179  1521780         1      1348303100

或者,您可以使用mask代替df.locquery

In [213]: df.query('date < date_threshold')
Out[213]: 
                    date   userid  watchers  date_threshold
repositoryid                                               
5910995       1348293168  1449180         1      1348293300
5911012       1348292421  2627657         1      1348292500
5911046       1367171000  1219404         1      1368722900
5911046       1368722792  1892225         2      1368722900
5911088       1348302179  1521780         1      1348303100