データサイエンス100本ノック~初心者未満の戦いpart9

これはデータサイエンティストの卵がわけもわからないまま100本ノックを行っていく奮闘録である。
完走できるか謎。~~途中で消えてもQiitaにあげてないだけと思ってください。~~


[100本ノックの記事](https://codezine.jp/article/detail/12456)
[100本ノックのガイド](https://github.com/The-Japan-DataScientist-Society/100knocks-preprocess/blob/master/docker/doc/100knocks_guide.pdf)

**ネタバレも含みますのでやろうとされている方は注意**

[よそごと](https://qiita.com/sola_wing529/items/bad361cdd0d11373b7be)やってて遅延

コレは見づらい！この書き方は危険！等ありましたら教えていただきたいです。~~心にダメージを負いながら~~糧とさせていただきます。

この解き方は間違っている！この解釈の仕方は違う！等もありましたらコメントください。

今回は４５～５１まで。
[[前回]](https://qiita.com/sola_wing529/items/9c32890f3177033692a4)４１～４４
[[目次付き初回]](https://qiita.com/sola_wing529/items/5fdbd97308dd88da28eb)

#45本目
ここから日付型－文字型－数字型の変換を行う問題が増えていきます
実は[よそごと](https://qiita.com/sola_wing529/items/bad361cdd0d11373b7be)やっていた時に少し日付型をいじることをやっていました。
よかった。脱線も無駄ではなかった。

今回ラストに同一サイトであっても欲しい情報→参考にしたページをまとめておきます。ページが飛びすぎててホントにわからん。

>P-045: 顧客データフレーム（df_customer）の生年月日（birth_day）は日付型（Date）でデータを保有している。これをYYYYMMDD形式の文字列に変換し、顧客ID（customer_id）とともに抽出せよ。データは10件を抽出すれば良い。

```mine45.py
df=df_customer.copy()
df['birth_day']=pd.to_datetime(df['birth_day']).dt.strftime('%Y%m%d')
df[['customer_id','birth_day']].head(10)

'''模範解答'''
pd.concat([df_customer['customer_id'],
           pd.to_datetime(df_customer['birth_day']).dt.strftime('%Y%m%d')],
          axis = 1).head(10)
```
問題やっている途中でバグったので`.copy()`を追加。`deepcopy`しなきゃいけないようならまた変更します。

今回は`.dt.strftime()`を使用（[参考](https://note.nkmk.me/python-datetime-usage/)）。
C言語で`printf`を多用していた身としてはフォーマット指定は結構好き。

ただ、何故か`df['birth_day']`に直接`.dt.strftime`をつなぐとエラーします。
なので`pd.to_datetime()`で明示してあげると(？)動きます

```typeCheck.py
type(df['birth_day'])
type(pd.to_datetime(df['birth_day']))
```
どっちも
>pandas.core.series.Series

なんですがねぇ

#46本目
>P-046: 顧客データフレーム（df_customer）の申し込み日（application_date）はYYYYMMD形式の文字列型でデータを保有している。これを日付型（dateやdatetime）に変換し、顧客ID（customer_id）とともに抽出せよ。データは10件を抽出すれば良い。

```mine46.py
df=df_customer.copy()
df['application_date']=pd.to_datetime(df['application_date'])
df[['customer_id','application_date']].head()
#df['application_date'].describe
#df['application_date'].apply(lambda x:x.year)

'''模範解答'''
pd.concat([df_customer['customer_id'],pd.to_datetime(df_customer['application_date'])], axis=1).head(10)
```

文字列型→日付型への変換 https://note.nkmk.me/python-pandas-datetime-timestamp/
途中で上手く変換できてるか試しています。

`.apply`と`lambda`を使った要素の取り出しは[こちら](https://note.nkmk.me/python-pandas-map-applymap-apply/)

#47本目
>P-047: レシート明細データフレーム（df_receipt）の売上日（sales_ymd）はYYYYMMDD形式の数値型でデータを保有している。これを日付型（dateやdatetime）に変換し、レシート番号(receipt_no)、レシートサブ番号（receipt_sub_no）とともに抽出せよ。データは10件を抽出すれば良い。

```mine47.py
df=df_receipt.copy()
df['sales_ymd']=pd.to_datetime(df['sales_ymd'].astype(str))
df[['receipt_no','receipt_sub_no','sales_ymd']].head(10)

'''模範解答'''
pd.concat([df_receipt[['receipt_no', 'receipt_sub_no']],
           pd.to_datetime(df_receipt['sales_ymd'].astype('str'))],axis=1).head(10)
```

数字→文字→日付型と変換してます。[数字→文字列への型変換](https://note.nkmk.me/python-pandas-str-num-conversion/)

#48本目
この問題、一か所だけ調べても分からない部分ありました。
>P-048: レシート明細データフレーム（df_receipt）の売上エポック秒（sales_epoch）は数値型のUNIX秒でデータを保有している。これを日付型（dateやdatetime）に変換し、レシート番号(receipt_no)、レシートサブ番号（receipt_sub_no）とともに抽出せよ。データは10件を抽出すれば良い。

```mine48.py
df=df_receipt.copy()
df['sales_epoch']=pd.to_datetime(df['sales_epoch'],unit='s')
df[['receipt_no','receipt_sub_no','sales_epoch']].head(10)

'''模範解答'''
pd.concat([df_receipt[['receipt_no', 'receipt_sub_no']],
           pd.to_datetime(df_receipt['sales_epoch'], unit='s')],axis=1).head(10)
```

まず、[エポック秒とは](https://note.nkmk.me/python-unix-time-datetime/)の記事を読み、最初「これ、intをそのまま時間に直すといけるんじゃね」と安直にやってみましたが出来ず、そのあとも色々試したけれどもギブアップ。答えを見ました。

すると出てきたのは`to_datetime('ｴﾎﾟｯｸ',unit='s')`
引数の`unit`が分からず調べてみたものの、[いつものサイト](https://note.nkmk.me/python-pandas-datetime-timestamp/)にはなく、仕方ないのでpandasのリファレンスページを開きました。

https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.to_datetime.html

>unitstr, default ‘ns’
The unit of the arg (D,s,ms,us,ns) denote the unit, which is an integer or float number. This will be based off the origin. Example, with unit=’ms’ and origin=’unix’ (the default), this would calculate the number of milliseconds to the unix epoch start.

英語ということもさておき分からん。引数として`D,s,ms,us,ns`を受け入れるというのはなんとなくわかるが、`s`がどのように作用してるかが全く分からん。
どなたか分かる方、参考ページでもいいので、教えてください。。。(もしかして読んでるページがリファレンスじゃない……？)

#49-51本目
似たような問題なので一気に行きます

>P-049: レシート明細データフレーム（df_receipt）の売上エポック秒（sales_epoch）を日付型（timestamp型）に変換し、"年"だけ取り出してレシート番号(receipt_no)、レシートサブ番号（receipt_sub_no）とともに抽出せよ。データは10件を抽出すれば良い。

>P-050: レシート明細データフレーム（df_receipt）の売上エポック秒（sales_epoch）を日付型（timestamp型）に変換し、"月"だけ取り出してレシート番号(receipt_no)、レシートサブ番号（receipt_sub_no）とともに抽出せよ。なお、"月"は0埋め2桁で取り出すこと。データは10件を抽出すれば良い。

>P-051: レシート明細データフレーム（df_receipt）の売上エポック秒（sales_epoch）を日付型（timestamp型）に変換し、"日"だけ取り出してレシート番号(receipt_no)、レシートサブ番号（receipt_sub_no）とともに抽出せよ。なお、"日"は0埋め2桁で取り出すこと。データは10件を抽出すれば良い。

```mine49.py
df=df_receipt.copy()
df['sales_epoch']=pd.to_datetime(df['sales_epoch'],unit='s')
df['sales_epoch']=df['sales_epoch'].dt.strftime('%Y')

df[['receipt_no','receipt_sub_no','sales_epoch']].head(10)

'''模範解答'''
pd.concat([df_receipt[['receipt_no', 'receipt_sub_no']],
           pd.to_datetime(df_receipt['sales_epoch'], unit='s').dt.strftime('%Y')],axis=1).head(10)

# %Y を　%m %d に変えれば月・日が出せる
```

エポック秒→日付型→文字列型抜き出しで49～51はできる

ただし、50,51の指定に
>なお、"月(日)"は0埋め2桁で取り出すこと。

とあるために

```
'''罠（ドボン）'''
pd.to_datetime(df['sales_epoch'], unit='s').dt.year
```

と、やると年は問題なく4桁で出るが月・日は0埋めにならない。
（逆に最初`%02d`とかやったけどやらなくても0埋めになった）

#今回はここまで

##参考ページ
- 数字→文字列への型変換 https://note.nkmk.me/python-pandas-str-num-conversion/
- 文字列型→日付型への変換 https://note.nkmk.me/python-pandas-datetime-timestamp/ (前半)
- 日付型→文字型変換 https://note.nkmk.me/python-datetime-usage/ (後半)
- `.apply`で要素の取り出し https://note.nkmk.me/python-pandas-map-applymap-apply/