4-5. pandas(DataFrame)-日付操作
pandasにおける日付型についての理解
dataframeでは、日付型項目をあくまでもobject型として保持している。 dtypesメソッドで全列の型を確認(hiredate列に注目)
df_emp.dtypes
empno int64
ename object
job object
manager float64
hiredate object
sal int64
comm float64
dept float64
dtype: object
列単体としてはSeries型であることを確認
type(df_emp['hiredate'])
<class 'pandas.core.series.Series'>
Seriesのdtypeを取ると、「O」
df_emp['hiredate'].dtype
dtype('O')
empnoだと「int64」というデータ型らしき値が戻る
df_emp['empno'].dtype
dtype('int64')
行・列を指定した、empno=7369,hiredate=1980/12/17 要素単体のデータ型は、、、
df_emp.loc[0,'hiredate'].dtype
AttributeError: 'str' object has no attribute 'dtype'
エラーになってしまう。 empnoだと、この方法でも「int64」が取れる
df_emp.loc[0,'empno'].dtype
dtype('int64')
type()を取ってみると、
type(df_emp.loc[0,'hiredate'])
<class 'str'>
⇒文字列
pd.to_datetime で明示的にdatetime/Timestamp型に変換
pd.to_datetime(df_emp['hiredate'])
0 1980-12-17
:
14 1985-03-17
Name: hiredate, dtype: datetime64[ns]
pd.to_datetime(df_emp.loc[0,'hiredate'])
Timestamp('1980-12-17 00:00:00')
読込時、データ型にdatetime64型を指定
df_emp = pd.read_csv('emp.csv', encoding='utf-8', parse_dates=[4])
# データ型を確認
df_emp['hiredate'].dtype
>> dtype('<M8[ns]')
type(df_emp.loc[0,'hiredate'])
>> <class 'pandas._libs.tslibs.timestamps.Timestamp'>
文字列による期間指定
SQL
SELECT * FROM emp WHERE hiredate >= TO_DATE('1981/05/01','YYYY/MM/DD')
pandas
df_emp.query('hiredate >= "1981/05/01"')
df_emp.query('hiredate <= "1981/05/01"')
dtアクセサを使用し、年を条件に抽出
SQL
SELECT * FROM emp WHERE TO_CHAR(hiredate, 'YYYY') = 1985
pandas
df_emp[pd.to_datetime(df_emp.loc[:,'hiredate']).dt.year == 1985]
dtアクセサを使用した月を条件にした抽出
SQL
SELECT * FROM emp WHERE TO_CHAR(hiredate, 'MM') = 4
pandas
df_emp[pd.to_datetime(df_emp.loc[:,'hiredate']).dt.month == 4]
dtアクセサを使用した日を条件にした抽出
SQL
SELECT * FROM emp WHERE TO_CHAR(hiredate, 'DD') = 17
pandas
df_emp[pd.to_datetime(df_emp.loc[:,'hiredate']).dt.day == 17]
dtアクセサを使用した曜日を条件にした抽出
SQL
SELECT * FROM emp WHERE TO_CHAR(hiredate, 'D') = 1
※ 1:日曜日~7:土曜日
pandas
df_emp[pd.to_datetime(df_emp.loc[:,'hiredate']).dt.dayofweek == 1]
※Monday=0, Sunday=6
※isoweekday() を使うと、Monday=1, Sunday=7
dtアクセサを使用して、その月の日数を取得
SQL
SELECT emp, TO_CHAR(LASTDAY(hiredate), 'DD') FROM emp
pandas
pd.to_datetime(df_emp.loc[:,'hiredate']).dt.daysinmonth
dtアクセサを使用して、その月の1日の日付を取得
SQL
SELECT emp, TRUNC(hiredate, 'Day') FROM emp;
pandas
※エラーになってしまう。
pd.to_datetime(df_emp.loc[:,'hiredate']).dt.round('MS') # ==> ng
pd.to_datetime(df_emp.loc[:,'hiredate']).dt.round('Y') # ==> ng
# 以下はエラーにならない。
pd.to_datetime(df_emp.loc[:,'hiredate']).dt.round('H') # ==> OK
pd.to_datetime(df_emp.loc[:,'hiredate']).dt.round('S') # ==> OK
pd.to_datetime(df_emp.loc[:,'hiredate']).dt.round('D') # ==> OK
日付の引き算(社員Aのhiredate-社員Bのhiredate)
SQL
SELECT emp1.hiredate - emp0.hiredate
FROM (SELECT ,empno, hiredate FROM emp WHERE empno = 7499) as emp1
,(SELECT ,empno, hiredate FROM emp WHERE empno = 7369) as emp0
pandas
pd.to_datetime(df_emp.loc[1,'hiredate']) - pd.to_datetime(df_emp.loc[0,'hiredate'])
日付の計算(1日加算)
SQL
SELECT hiredate + 1 FROM emp;
pandas
import datetime as dt
diffdate = dt.timedelta(days=1)
pd.to_datetime(df_emp.loc[:,'hiredate']) + diffdate
日付の計算(1ヶ月加算)
SQL
SELECT ADD_MONTHS(hiredate, 1) FROM emp;
pandas
from dateutil import relativedelta
diffdate = relativedelta.relativedelta(months=1)
pd.to_datetime(df_emp.loc[:,'hiredate']).apply(lambda x: x + diffdate)
<< 参考サイト >>
Python で前月同日・前月末日を求める
https://blaue-fuchs.hatenadiary.org/entry/20110814/1313310157
Pythonで日付の加算、特にnヶ月後やn年後の日付を求める方法
https://analytics-note.xyz/programming/relativedelta/
日付の計算(当月1日)
SQL
SELECT TRUNC(hiredate, 'MONTHS') FROM emp;
pandas
from dateutil import relativedelta
pd.to_datetime(df_emp.loc[:,'hiredate']).apply(lambda x: x.replace(day=1))
日付の計算(月末)
SQL
SELECT LASTDAY(hiredate) FROM emp;
pandas
※翌月同日を算出し、その月の1日を取得。更にその前日を算出する。
from dateutil import relativedelta
addmonth1 = relativedelta.relativedelta(months=1)
diffdate = relativedelta.relativedelta(days=1)
pd.to_datetime(df_emp.loc[:,'hiredate']).apply(lambda x: (x + addmonth1).replace(day=1)-diffdate)
日付の計算(年末)
SQL
SELECT TRUNC(ADD_MONTHS(hiredate, 12), 'YEAR')-1 FROM emp;
pandas
※翌年同日を算出し、その年の1月1日に置換。更にその前日を算出する。
from dateutil import relativedelta
addmonth12 = relativedelta.relativedelta(years=1)
diffdate = relativedelta.relativedelta(days=1)
pd.to_datetime(df_emp.loc[:,'hiredate']).apply(lambda x: (x + addmonth12).replace(month=1).replace(day=1)-diffdate)
※別の方式。当月1日に変換し、それに13-月数を加算して、翌年1月1日を算出。その前日で年末を求める。
pd.to_datetime(df_emp.loc[:,'hiredate']).apply(lambda x: x.replace(day=1) + relativedelta.relativedelta(months=13-x.month)-diffdate)
strftime() で文字列型に変換
SQL
SELECT emp, TO_CHAR(hiredate, 'YYYY-MM-DD') FROM emp;
pandas
pd.to_datetime(df_emp.loc[:,'hiredate']).dt.strftime('%Y-%m-%d')
pd.to_datetime(df_emp.loc[:,'hiredate']).dt.strftime('%Y // %m // %d //')
pd.to_datetime(df_emp.loc[:,'hiredate']).dt.strftime('%Y年%m月%d日')
## ↓年月日の表示が上手くいかない場合(Windows)
pd.to_datetime(df_emp.loc[:,'hiredate']).dt.strftime('%Y年%m月%d日'.encode('unicode-escape').decode()) \
.str.encode('cp932').str.decode("unicode-escape")
Windowsの場合は、書式文字列に年月日等のマルチバイト文字列を使用した場合に、 UnicodeEncodeError: 'locale' codec can't encode character '\u5e74' が出る場合があります('\u5e74'は「年」の文字コード表示)。 下記のような対応で解決する場合がありますが、詳細は環境等々の状況により異なりますので個別に確認ください。
chcp 65001 # Windowsの場合にコンソールのエンコーディングを指定する(戻すときはchcp 932)
python -X utf8 # python起動時にコンソールの文字コードを指定
import datetime as dt
import locale
# localeモジュールで時間のロケールを'ja_JP.UTF-8'に変更する
locale.setlocale(locale.LC_TIME, 'ja_JP.UTF-8')
d = dt.date(2022, 12, 31)
print(d.strftime('%A')) # => '土曜日'
print(d.strftime('%Y年%m月%d日')) # ==> 2022年12月31日
# これでもダメな場合は、
print(d.strftime('%Y年%m月%d日'.encode('unicode-escape').decode()).encode().decode("unicode-escape"))
<< 参考サイト >>
【Python】曜日を取得する(英語&日本語)
https://qiita.com/_masa_u/items/e104d42bd6f200d3b959
Windows 上の Python で UTF-8 をデフォルトにする
https://qiita.com/methane/items/9a19ddf615089b071e71
time.strftime で UnicodeEncodeError が出るんだが
https://itasuke.hatenadiary.org/entry/20141103/p1
Windows上のPythonのdatetime.strftimeで日本語を使うとエラーになる?
https://ja.stackoverflow.com/questions/44597/windows%E4%B8%8A%E3%81%AEpython%E3%81%AEdatetime-strftime%E3%81%A7%E6%97%A5%E6%9C%AC%E8%AA%9E%E3%82%92%E4%BD%BF%E3%81%86%E3%81%A8%E3%82%A8%E3%83%A9%E3%83%BC%E3%81%AB%E3%81%AA%E3%82%8B