web-dev-qa-db-ja.com

欠落している日付をpandasデータフレームに追加します

私のデータには、特定の日に複数のイベントを設定することも、日付にイベントを設定しないこともできます。これらのイベントを取得し、日付ごとにカウントを取得してプロットします。ただし、それらをプロットすると、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
87
KHibma

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
...
194
unutbu

より迅速な回避策は、 .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
24
Brad Solomon

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

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

代わりに、.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を列シリーズで使用して空白を埋めることができます。

21
Nick Edgar

別のアプローチは resample です。これは、欠落している日付に加えて重複した日付を処理できます。例えば:

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

resamplegroupbyのような遅延操作なので、別の操作を続ける必要があります。この場合、meanはうまく機能しますが、maxsumなど、他の多くのpandasメソッドも使用できます。

元のデータを次に示しますが、「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として残しましたが、OPの要求に応じてfillna(0)を追加してNaNをゼロに置き換えるか、代わりにinterpolate()などを使用して非ゼロで埋めることができます隣接する行に基づいた値。

13
JohnE

不足している日付をデータフレームに入力するニースの方法は、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
4
eiTan LaVi