6

日付といくつかのカテゴリ (以下の例では簡単にするために 1 つ) で構成される MultiIndex があり、各カテゴリには何らかのプロセスの値を持つ時系列があるとします。観測があったときにのみ値があり、その日付に観測がなかったときはいつでも「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),
    (datetime.date(2013, 2, 10), 2, 7),
    (datetime.date(2013, 2, 11), 2, 7),
    (datetime.date(2013, 2, 13), 1, 2),
    (datetime.date(2013, 2, 13), 2, 3)],
    columns = ['date', 'category', 'value'])
df.set_index(['date', 'category'], inplace=True)
print df
print df.unstack().reindex(all_dates).fillna(0).stack()
# insert 0 values for missing dates
print all_dates

                        value
date       category       
2013-02-10 1             4
           2             7
2013-02-11 2             7
2013-02-13 1             2
           2             3

                      value
            category       
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
[datetime.date(2013, 2, 13), datetime.date(2013, 2, 12),
    datetime.date(2013, 2, 11),     datetime.date(2013, 2, 10)]

同じことを達成するためのよりスマートな方法を知っている人はいますか?

編集:同じことを達成する別の可能性を見つけました:

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
4

2 に答える 2

12

必要なインデックス レベルのデカルト積に基づいて、新しいマルチ インデックスを作成できます。次に、新しいインデックスを使用してデータ フレームのインデックスを再作成します。

(date_index, category_index) = df.index.levels
new_index = pd.MultiIndex.from_product([all_dates, category_index])
new_df = df.reindex(new_index)

# Optional: convert missing values to zero, and convert the data back
# to integers. See explanation below.
new_df = new_df.fillna(0).astype(int)

それでおしまい!新しいデータ フレームには、可能なすべてのインデックス値があります。既存のデータは正しく索引付けされています。

詳細な説明については、続きをお読みください。


説明

サンプル データの設定

import datetime as dt
import pandas as pd

days= 4
#List of all dates that should be in the index
all_dates = [dt.date(2013, 2, 13) - dt.timedelta(days=x)
    for x in range(days)]
df = pd.DataFrame([
    (dt.date(2013, 2, 10), 1, 4),
    (dt.date(2013, 2, 10), 2, 7),
    (dt.date(2013, 2, 11), 2, 7),
    (dt.date(2013, 2, 13), 1, 2),
    (dt.date(2013, 2, 13), 2, 3)],
    columns = ['date', 'category', 'value'])
df.set_index(['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

新しいインデックスを作成

from_productを使用して、新しいマルチ インデックスを作成できます。この新しいインデックスは、関数に渡すすべての値のデカルト積です。

(date_index, category_index) = df.index.levels

new_index = pd.MultiIndex.from_product([all_dates, category_index])

再インデックス

新しいインデックスを使用して、既存のデータ フレームのインデックスを再作成します。

すべての可能な組み合わせが表示されます。欠損値は null (NaN) です。

new_df = df.reindex(new_index)

これで、展開され、再インデックスされたデータ フレームは次のようになります。

              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

整数列のヌル

新しいデータ フレームのデータが int から float に変換されていることがわかります。Pandas は、整数列に null を含めることはできません。オプションで、すべての null を 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
于 2016-12-22T03:05:49.100 に答える
3

この回答をチェックしてください: How to fill the missing record of Pandas dataframe in pythonic way?

次のようなことができます:

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)
于 2013-02-13T20:05:21.440 に答える