欠落している日付をパンダデータフレームに追加する


126

私のデータには、特定の日付に複数のイベントがあるか、日付にイベントがありません。私はこれらのイベントを受け取り、日付ごとにカウントを取得してプロットします。しかし、それらをプロットすると、2つのシリーズが常に一致するとは限りません。

idx = pd.date_range(df['simpleDate'].min(), df['simpleDate'].max())
s = df.groupby(['simpleDate']).size()

上記のコードでは、idxはたとえば30日付の範囲になります。2013 年9月1日から2013 年9月30日までただし、特定の日付にイベントが発生しなかったため、Sは25日または26日しかありません。次に、プロットしようとするとサイズが一致しないため、AssertionErrorが発生します。

fig, ax = plt.subplots()    
ax.bar(idx.to_pydatetime(), s, color='green')

これに取り組む適切な方法は何ですか?IDXから値のない日付を削除しますか、それとも(そうしたいのですが)、0のカウントで欠落している日付をシリーズに追加しますか?値が0の30日間の完全なグラフが必要です。このアプローチが正しい場合、開始方法に関する提案はありますか?何らかの動的reindex機能が必要ですか?

これがSdf.groupby(['simpleDate']).size() )のスニペットです。04と05のエントリがないことに注意してください。

09-02-2013     2
09-03-2013    10
09-06-2013     5
09-07-2013     1

回答:


254

あなたは使うことができますSeries.reindex

import pandas as pd

idx = pd.date_range('09-01-2013', '09-30-2013')

s = pd.Series({'09-02-2013': 2,
               '09-03-2013': 10,
               '09-06-2013': 5,
               '09-07-2013': 1})
s.index = pd.DatetimeIndex(s.index)

s = s.reindex(idx, fill_value=0)
print(s)

収量

2013-09-01     0
2013-09-02     2
2013-09-03    10
2013-09-04     0
2013-09-05     0
2013-09-06     5
2013-09-07     1
2013-09-08     0
...

23
reindex素晴らしい機能です。(1)ラベルの新しいセットに一致するように既存のデータを並べ替え、(2)以前にラベルが存在しなかった場所に新しい行を挿入する、(3)欠落しているラベルのデータを埋める(順方向/逆方向の埋め込みを含む)(4)行を選択するラベルで!
unutbu 2013年

@unutbuこれも私が質問した質問の一部に答えます、ありがとう!しかし、イベントのある日付のリストを動的に作成する方法を知っているかどうか疑問に思いましたか?
Nick Duddy 2017年

2
ただし、再インデックスには1つの問題(またはバグ)があります。1970年1月1日より前の日付では機能しないため、この場合はdf.resample()が完全に機能します。
Sergey Gulbin 2017

1
IDXは、手動で開始日と終了日を入力スキップするためにあなたの代わりにこれを使用する可能性がありますidx = pd.date_range(df.index.min(), df.index.max())
朝礼

:あなたの検索救うために、ここでのドキュメントへのリンクを削除pandas.pydata.org/pandas-docs/stable/reference/api/...
害テモルダー

40

より迅速な回避策はを使用すること.asfreq()です。これは、内で呼び出すための新しいインデックスの作成を必要としません.reindex()

# "broken" (staggered) dates
dates = pd.Index([pd.Timestamp('2012-05-01'), 
                  pd.Timestamp('2012-05-04'), 
                  pd.Timestamp('2012-05-06')])
s = pd.Series([1, 2, 3], dates)

print(s.asfreq('D'))
2012-05-01    1.0
2012-05-02    NaN
2012-05-03    NaN
2012-05-04    2.0
2012-05-05    NaN
2012-05-06    3.0
Freq: D, dtype: float64

1
私はこの方法が本当に好きです。date_range最初と最後のインデックスを開始と終了として暗黙的に使用するので、呼び出す必要がありません(これはほとんど常に必要です)。
Michael Hays

とても清潔でプロフェッショナルな方法。その後も補間を使用してうまく動作します。
msarafzadeh

26

1つの問題は、reindex重複する値があると失敗することです。日付でインデックス付けするタイムスタンプ付きのデータを処理しているとします。

df = pd.DataFrame({
    'timestamps': pd.to_datetime(
        ['2016-11-15 1:00','2016-11-16 2:00','2016-11-16 3:00','2016-11-18 4:00']),
    'values':['a','b','c','d']})
df.index = pd.DatetimeIndex(df['timestamps']).floor('D')
df

収量

            timestamps             values
2016-11-15  "2016-11-15 01:00:00"  a
2016-11-16  "2016-11-16 02:00:00"  b
2016-11-16  "2016-11-16 03:00:00"  c
2016-11-18  "2016-11-18 04:00:00"  d

2016-11-16日付が重複しているため、インデックスを再作成しようとしました:

all_days = pd.date_range(df.index.min(), df.index.max(), freq='D')
df.reindex(all_days)

失敗します:

...
ValueError: cannot reindex from a duplicate axis

(これにより、インデックスが重複していることを意味し、それ自体が重複しているわけではありません)

代わりに、を使用.locして、範囲内のすべての日付のエントリを検索できます。

df.loc[all_days]

収量

            timestamps             values
2016-11-15  "2016-11-15 01:00:00"  a
2016-11-16  "2016-11-16 02:00:00"  b
2016-11-16  "2016-11-16 03:00:00"  c
2016-11-17  NaN                    NaN
2016-11-18  "2016-11-18 04:00:00"  d

fillna 必要に応じて、列シリーズで空白を埋めるために使用できます。


日付の列が含まれている場合は何をすべきか上の任意のアイデアBlanksNULLSdf.loc[all_days]その場合は機能しません。
フルカンハシム

1
list-likesを.locまたは[]に渡し、ラベルが欠けていると、将来KeyErrorが発生します。代わりに.reindex()を使用できます。ここではドキュメントを参照してください:pandas.pydata.org/pandas-docs/stable/...
Dmitriiマガス

19

別の方法はですresample。これは、欠落した日付に加えて重複した日付を処理できます。例えば:

df.resample('D').mean()

resampleのような遅延操作なgroupbyので、別の操作を続ける必要があります。この場合meanはうまく機能しますがmax、などの他の多くのパンダメソッドを使用することもできます。sumなど、

これが元のデータですが、「2013-09-03」の追加エントリがあります。

             val
date           
2013-09-02     2
2013-09-03    10
2013-09-03    20    <- duplicate date added to OP's data
2013-09-06     5
2013-09-07     1

そしてここに結果があります:

             val
date            
2013-09-02   2.0
2013-09-03  15.0    <- mean of original values for 2013-09-03
2013-09-04   NaN    <- NaN b/c date not present in orig
2013-09-05   NaN    <- NaN b/c date not present in orig
2013-09-06   5.0
2013-09-07   1.0

これがどのように機能するかを明確にするために、不足している日付をNaNとして残しましたが、追加fillna(0)して、OPからの要求に応じてNaNをゼロに置き換えるか、または代わりinterpolate()に、隣接する行に基づいてゼロ以外の値で埋めるようなものを使用できます。


6

ここでは素敵なあなたの選択はで、データフレームに欠落している日付を記入する方法ですfill_valuedays_backを記入し、ソート順(date_orderデータフレームの並べ替えに使用するには):

def fill_in_missing_dates(df, date_col_name = 'date',date_order = 'asc', fill_value = 0, days_back = 30):

    df.set_index(date_col_name,drop=True,inplace=True)
    df.index = pd.DatetimeIndex(df.index)
    d = datetime.now().date()
    d2 = d - timedelta(days = days_back)
    idx = pd.date_range(d2, d, freq = "D")
    df = df.reindex(idx,fill_value=fill_value)
    df[date_col_name] = pd.DatetimeIndex(df.index)

    return df
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.