Python 为多索引中缺少的日期插入0值

Python 为多索引中缺少的日期插入0值,python,pandas,Python,Pandas,让我们假设我有一个多索引,它由日期和一些类别组成(下面的例子中有一个是为了简单起见),对于每个类别,我有一个带有一些进程值的时间序列。 我只有在有观察时才有一个值,现在我想在该日期没有观察时添加一个“0”。 我找到了一种似乎效率很低的方法(堆叠和拆垛,这将在数百万个类别的情况下创建许多列) 有人知道更聪明的方法来达到同样的目的吗 编辑:我发现了实现同样目标的另一种可能性: import datetime as dt import pandas as pd days= 4 #List of al

让我们假设我有一个多索引,它由日期和一些类别组成(下面的例子中有一个是为了简单起见),对于每个类别,我有一个带有一些进程值的时间序列。 我只有在有观察时才有一个值,现在我想在该日期没有观察时添加一个“0”。 我找到了一种似乎效率很低的方法(堆叠和拆垛,这将在数百万个类别的情况下创建许多列)

有人知道更聪明的方法来达到同样的目的吗

编辑:我发现了实现同样目标的另一种可能性:

import datetime as dt
import pandas as pd

days= 4
#List of all dates that should be in the index
all_dates = [datetime.date(2013, 2, 13) - dt.timedelta(days=x) for x in range(days)]
df = pd.DataFrame([(datetime.date(2013, 2, 10), 1, 4, 5),
(datetime.date(2013, 2, 10), 2,1, 7),
(datetime.date(2013, 2, 10), 2,2, 7),
(datetime.date(2013, 2, 11), 2,3, 7),
(datetime.date(2013, 2, 13), 1,4, 2),
(datetime.date(2013, 2, 13), 2,4, 3)],
columns = ['date', 'category', 'cat2', 'value'])
date_col = 'date'
other_index = ['category', 'cat2']
index = [date_col] + other_index
df.set_index(index, inplace=True)
grouped = df.groupby(level=other_index)
df_list = []
for i, group in grouped:
    df_list.append(group.reset_index(level=other_index).reindex(all_dates).fillna(0))
print pd.concat(df_list).set_index(other_index, append=True)

                    value
           category cat2       
2013-02-13 1        4         2
2013-02-12 0        0         0
2013-02-11 0        0         0
2013-02-10 1        4         5
2013-02-13 0        0         0
2013-02-12 0        0         0
2013-02-11 0        0         0
2013-02-10 2        1         7
2013-02-13 0        0         0
2013-02-12 0        0         0
2013-02-11 0        0         0
2013-02-10 2        2         7
2013-02-13 0        0         0
2013-02-12 0        0         0
2013-02-11 2        3         7
2013-02-10 0        0         0
2013-02-13 2        4         3
2013-02-12 0        0         0
2013-02-11 0        0         0
2013-02-10 0        0         0
检查此答案:

您可以执行以下操作:

import datetime
import pandas as pd

#make an empty dataframe with the index you want
def get_datetime(x):
    return datetime.date(2013, 2, 13)- datetime.timedelta(days=x)

all_dates = [ get_datetime(x) for x in range(4)]
categories = [1,2,3,4]
index = [ [date, cat] for cat in categories for date in all_dates ]

#this df will be just an index
df = pd.DataFrame(index)
df =print df.set_index([0,1])
df.columns = ['date', 'category']
df = df.set_index(['date', 'category'])


#now if your original df is called df_original you can reindex against the other values
df_orig = df_orig.reindex_axis(df.index)

#and to add zeros
df_orig.fillna(0)

您可以根据所需索引级别的笛卡尔乘积创建新的多重索引。然后,使用新索引重新索引数据帧

(日期索引、类别索引)=df.index.levels
新索引=pd.MULTINDEX.from产品([所有日期,类别索引])
新建索引df=df.reindex(新建索引)
#可选:将缺少的值转换为零,然后将数据转换回零
#到整数。见下面的解释。
new_df=new_df.fillna(0).astype(int)
就这样!新数据帧具有所有可能的索引值。已正确索引现有数据

请继续阅读以获得更详细的解释


解释 设置示例数据
将日期时间导入为dt
作为pd进口熊猫
天数=4天
#应在索引中的所有日期的列表
所有日期=[dt.date(2013,2,13)-dt.timedelta(天数=x)
对于范围内的x(天)]
df=pd.DataFrame([
(dt.日期(2013年2月10日)、1月4日),
(dt.日期(2013年2月10日),2月7日),
(dt.日期(2013年2月11日),2月7日),
(dt.日期(2013年2月13日)、1月2日),
(dt.日期(2013年2月13日),2月3日)],
列=[“日期”、“类别”、“值”])
df.set_索引(['date','category'],inplace=True)
下面是示例数据的样子

                     value
date       category
2013-02-10 1             4
           2             7
2013-02-11 2             7
2013-02-13 1             2
           2             3
制作新索引 使用该方法,我们可以创建一个新的多索引。此新索引是传递给函数的所有值的索引

(date_index, category_index) = df.index.levels

new_index = pd.MultiIndex.from_product([all_dates, category_index])
重新索引 使用新索引重新索引现有数据帧

所有可能的组合现在都存在。缺少的值为空(NaN)

现在,扩展的、重新索引的数据帧如下所示:

              value
2013-02-13 1    2.0
           2    3.0
2013-02-12 1    NaN
           2    NaN
2013-02-11 1    NaN
           2    7.0
2013-02-10 1    4.0
           2    7.0
整数列中的空值 您可以看到,新数据帧中的数据已从整数转换为浮点。或者,我们可以将所有空值转换为0,并将数据转换回整数

new_df = new_df.fillna(0).astype(int)
结果

              value
2013-02-13 1      2
           2      3
2013-02-12 1      0
           2      0
2013-02-11 1      0
           2      7
2013-02-10 1      4
           2      7

我喜欢你的堆叠/取消堆叠方法。我不确定是否有更好的方法来添加行。如果你知道所有的类别,也许你可以制作一个包含所有日期/类别的DF,并将其与包含DF的数据合并。这将留下可以用零填充的NAs。我不知道这样做是否会更快……在组中进行迭代的版本不会为我的本地数据集抛出memoryerror(堆栈/取消堆栈版本会),构建元组列表实际上是我想要避免的事情。对于多索引,这可能会很快导致内存错误(我曾经有过一次),因为它构建了一个随着级别和级别_值的数量而增长的列表,并且操作本身要容易得多(对于每个唯一的组键,添加所有不存在的日期)。迭代组并创建包含所有日期的小dfs,然后连接可能更方便内存。我在问题中添加了迭代和连接。
new_df = new_df.fillna(0).astype(int)
              value
2013-02-13 1      2
           2      3
2013-02-12 1      0
           2      0
2013-02-11 1      0
           2      7
2013-02-10 1      4
           2      7