3

我有一个大熊猫数据框(约 1300 万行),其中包含各种项目的数据,每个项目都有不同月份的观察结果。这些项目根据相应行的数量(即具有观察数据的月份)而变化,并且月份可能是连续的,也可能不是连续的。高度缩写的简化示例:

                          x         y
item_id date
4       2006-01-01  5.69368  0.789752
        2006-02-01  5.67199  0.786743
        2006-03-01  5.66469  0.783626
        2006-04-01  5.69427  0.782596
        2006-05-01  5.70198  0.781670
5       2006-05-01  3.16992  1.000000
        2006-07-01  3.25000  0.978347

我需要为数据完成以下工作:对于每个项目,从该项目的第一个观察到的行向前填充观察到指定的最大日期。因此,给定上面的示例,所需的输出如下:

                          x         y
item_id
4       2006-01-01  5.69368  0.789752
        2006-02-01  5.67199  0.786743
        2006-03-01  5.66469  0.783626
        2006-04-01  5.69427  0.782596
        2006-05-01  5.70198  0.781670
        2006-06-01  5.70198  0.781670
        2006-07-01  5.70198  0.781670
        2006-08-01  5.70198  0.781670
        2006-09-01  5.70198  0.781670
        2006-10-01  5.70198  0.781670
        2006-11-01  5.70198  0.781670
        2006-12-01  5.70198  0.781670
5       2006-05-01  3.16992  1.000000
        2006-06-01  3.16992  1.000000
        2006-07-01  3.25000  0.978347
        2006-08-01  3.25000  0.978347
        2006-09-01  3.25000  0.978347
        2006-10-01  3.25000  0.978347
        2006-11-01  3.25000  0.978347
        2006-12-01  3.25000  0.978347

为了便于进一步分析,我需要将日期索引转换为简单的数字索引(我们将其称为“seq”),这样最终的结果是:

                  x         y
item_id seq
4       0   5.69368  0.789752
        1   5.67199  0.786743
        2   5.66469  0.783626
        3   5.69427  0.782596
        4   5.70198  0.781670
        5   5.70198  0.781670
        6   5.70198  0.781670
        7   5.70198  0.781670
        8   5.70198  0.781670
        9   5.70198  0.781670
        10  5.70198  0.781670
        11  5.70198  0.781670
5       0   3.16992  1.000000
        1   3.16992  1.000000
        2   3.25000  0.978347
        3   3.25000  0.978347
        4   3.25000  0.978347
        5   3.25000  0.978347
        6   3.25000  0.978347
        7   3.25000  0.978347

(这样做的目的是让我对项目的第一个、第二个、...、第 n 个观察值进行平均)。无论如何,如果我只对数据的一个子集进行操作,我有一个可以正常工作的解决方案:

df = pd.read_table(filename,sep='\s*',header=None,names=['item_id','date','x','y'],index_col=['item_id','date'],parse_dates='date')
maxDate = '2006-12-01'
def switchToSeqIndex(df):
    minDate = df.index[0][1] # get the first observed date
    return df.reset_index(level='item_id',drop=True).reset_index(). \
            set_index('date').reindex(pd.date_range(minDate,maxDate,freq='MS'), \ 
            method='ffill').reset_index('date',drop=True)
df_fixed = df.groupby(level='item_id').apply(switchToSeqIndex)
df_fixed.index.names[1]='seq'

原则上这很好,并且会生成正确的输出,但是当我尝试对整个数据集(1300 万行,通过重新索引扩展大量数据)执行操作时,内存使用失控(用20GB 内存)。

那么,我的问题是如何在减少内存开销的同时做到这一点。我认为问题在于尝试使用 groupby/apply 方法执行重新索引,但我不知道替代方法是什么。似乎应该有办法我可以迭代地做类似的事情,这需要更少的内存,但我不知道如何去做。

4

1 回答 1

0

我将通过创建一个DataFrame只包含所需的完整日期集来解决这个问题。DataFrame然后按 ID对原始数据进行分组,并在日期上加入,DataFrame使用outer, 来拉入任何缺失的日期(因此,xy用于NaN必须通过连接拉入日期的行)。

之后,按 ID 分组,按您需要的任何顺序按日期排序,然后只需使用常规调用fillna来转发填充xy列中的所有 NaN 值。

我之前已经用 > 2 亿行的 s 完成了这种任务DataFrame(在具有 12 GB RAM 的系统上),是的,它不是瞬时的,但它也不够慢。

一些伪代码:

df = your_current_df.reset_index().set_index("item_id")
# Or, use something smarter with unstack(level=1) and possibly some 
# in-place option.

# I assume this puts the dates into a regular column called 'date'

# Do stuff to make all the dates you could possibly need
dates_df = pandas.DataFrame(...)

df = pandas.merge(df, dates_df, left_on="date", right_on="date", how="outer")
df.sort("date", ascending=True, inplace=True)
df.groupby("item_id").fillna(method="ffill")
于 2013-11-01T20:54:52.310 回答