私のデータには、特定の日に複数のイベントを設定することも、日付にイベントを設定しないこともできます。これらのイベントを取得し、日付ごとにカウントを取得してプロットします。ただし、それらをプロットすると、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
関数が必要ですか?
S(df.groupby(['simpleDate']).size()
)のスニペットがあります。04と05のエントリがないことに注意してください。
09-02-2013 2
09-03-2013 10
09-06-2013 5
09-07-2013 1
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
...
より迅速な回避策は、 .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つの問題は、値が重複している場合、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
を列シリーズで使用して空白を埋めることができます。
別のアプローチは resample
です。これは、欠落している日付に加えて重複した日付を処理できます。例えば:
df.resample('D').mean()
resample
はgroupby
のような遅延操作なので、別の操作を続ける必要があります。この場合、mean
はうまく機能しますが、max
、sum
など、他の多くの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()
などを使用して非ゼロで埋めることができます隣接する行に基づいた値。
不足している日付をデータフレームに入力するニースの方法は、fill_value
、days_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