pandas datetime

##時系列データのpandasでの処理方法
時系列データを取り込んだ処理をする度に毎回調べる羽目になっていますので、いい加減メモっておきます。

##### 1. 時間が'YYYYmmddHHMMSSfff'として与えられた場合の処理

```python3:pandasのdfをdatetimeに変換する例1
import pandas as pd
# import datetime は不要です。

# sampleデータです。
sample=[
        20180808121545000,
        20180808121545200,
        20180808121546400,
        20180808121745600]

df=pd.DataFrame(sample,columns={'date'})

# datetime型への変換処理は、pandasのto_datetimeを使います。
#df.date.to_datetimeではできないのが少しややこしい。
df.date=pd.to_datetime(df.date,format='%Y%m%d%H%M%f')
```
この様に、datetimeに変換する場合、pandasのto_datetimeという変換コマンドがあります.to_datetimeのオプションであるformatについてはmonth/dayを意味する'%m%d'が小文字で、時間を表hour/minute/secondが'%H%M%S'大文字になります。秒の少数点以下は'%f'（'%F'ではない）とします。

##### 2. 時間が'YYYY/mm/ddTHH:MM:SS.fff'として与えられた場合

```python3:pandasのdfをdatetimeに変換する例2
import pandas as pd
date_str=[
    '2018/08/08T12:15:45.000',
    '2018/08/08T12:15:45.200',
    '2018/08/08T12:17:45.600']
df=pd.DataFrame(date_str,columns={'dtime'})

df.dtime=pd.to_datetime(df.dtime,format='%Y/%m/%dT%H:%M:%S.%f')

df.date=pd.to_datetime(df.date,format='%Y%m%dT%H%M%f')
```
例１と同じです。formatの文字列を変更すれば対応できます。
formatの主な例は下記にまとめておきます。

| 書式 | 説明 |
|:--|:--|
| %Y | ４桁の年 |
| %y | ２桁の年 |
| %m | ２桁の月[01,02,...,12] |
| %d | 日[2桁] |
| %H | 時間[24時間] |
| %I | 時間[12時間] |
| %M | 分 |
| %S | 秒 |
| %z | タイムゾーン UTCのずれの分[+HHMM] |
| %F | %Y-%m-%d のalias |
| %f | sub-second [0.000 sec] |


###daltatime型をsecond単位に換算する場合
例えば時系列データを回帰を行いたいのように時間の情報を計算に使いたい場合には、データ取得開始時刻からの経過時間を秒に変換する必要が出る場合があります。時間を初期時間で引けば経過時間になりますが、datetime型同士を引き算すると、データ型が新たにtimedelta型として扱われます。この型にはtotal_seconds()というメソットが用意されていて、次の様に時間差を秒(np.float64)に換算することができます。

```py3:total_seconds()を用いて、差分を秒単位で計算する場合
df['dt']=(df.dtime-df.dtime[0])
# df.dt.total_seconds() はエラーになりますので下記を使います。
df['dt']=[i.total_seconds() for i in df.dt]

# forを使わないでも下記のようにfloat64にキャストできます。
df['dt']=df['dt']/np.timedelta64(1, 's')

```
Dataframeの要素一つ一つには.total_seconds()メソットが利用できますが、 pandasのDataframe自体には.total_seconds()は用意されていないので、コマンド一発で秒に変換することができません。なので、上記の様に要素毎に.total_seconds()を用いて変換しています。
forを使わない方法ではnp.timedalta64(1,'s')で割ることでfloatに変換できるようです。


##サンプリングレートを揃える場合
取得したデータのdtが一定でない場合もあります。これを揃えるには、resample()メソッドを使いますが、indexはdatetime型になっている必要があります。

```py3:resample()の使い方
# resampleを使うには、dfのindexを時間情報に必要があります。
df.index=df.dtime

# 100msにsampling rate を揃えています。値は平均値を使います。
# .ffill(bfill） : 値がない時刻は、過去（未来）の時刻での値を当てはめます。
#指定しない場合はデフォルトではNaNが入ってしまいます.

#up-samplingの場合
df.resample('100ms').ffill()

#1秒毎に区間平均を取りdown-samplingする場合、
df.resample('1s').mean()
```

リサンプリングの引数にサンプリングレートを指定することで、ダウンサンプリングもアップサンプリングも可能です。

| resampleの引数| 説明 |
|:--|:--|
| M | 月毎 |
| W | 週毎 |
| D | 日毎 |
| H | 時間 |
| T, min | 分毎 |
| S | 秒毎 |
| L, ms | ミリ秒毎 |
| U, us | マイクロ秒毎 |
| N, ns | ナノ秒毎 |

resampleでup-samplingした場合、defaultではデータが存在しない時刻の値にNanが使われます。up-samplingではbfillか、ffillを使うことでNanの代わりに値を入れることができます。とりあえずゼロ次ホールドで値を入れておきたい場合、通常はffillを使います。bfillは因果律を破る向きにNanを未来の値で埋めますのであまり利用しましせん。

down-samplingでは、データを減らします。その際に各binに含まれる場合の平均値を取るならば.mean()を利用し、中央値を取るならmedian()を使います。

|メソッド|説明 |
|:--|:--|
| bfill | Backward fill　(up-sampling時)に未来のデータで埋める |
| ffill | Forward fill  (up-sampling時)に過去のデータで埋める|
| mean | down samplingで、区間（ビン）毎に平均値を取る場合 |
| median | down samplingで中央値を取る場合 |
| ohlc | ローソク足を使う時 |

## resampling()を使いたい場合
時系列データでなくてもresamplingを使うとデータのup/down-samplingできる。
サンプリングに用いるデータをpd.to_datetime型に変換する。

```py3:resampleを使った例
#
df=pd.DataFrame([0.0,1.,2.,3],columns={'date'})

# とりあえずdatetimeに変換し、resampleを使うため仮のindexに指定します。
df.index=pd.to_datetime(df.date,format='%S.%f')
df=df.resample('100ms').ffill()
#indexをリセットします。
df.reset_index(drop=True)
```
* 参考

https://docs.scipy.org/doc/numpy-dev/reference/arrays.datetime.html#datetime-and-timedelta-arithmetic