pandas to_datetime()の使い方|文字列の日付変換と format・NaT 対処を初心者向けに解説

CSVを読み込んだあと、日付列が文字列のままで困ったことはありませんか?

見た目は日付でも、object 型のままだと、日付順に並び替えられなかったり、条件抽出や月ごとの集計がしにくかったりします。
そんなときに使うのが pd.to_datetime() です。

結論からいうと、日付列を日付として扱いたいなら、まず pd.to_datetime() を使います。

特に、次の3つを先に押さえると迷いにくいです。

  • 日付として比較・抽出・集計したい → pd.to_datetime()
  • 書式がそろっている → format= を検討する
  • 変換できない値を洗い出したい → errors="coerce" を使う

pd.to_datetime() の目的は、見た目が日付の文字列を、並び替え・抽出・集計に使える“本当の日付データ”へ変えることです。

この記事では、pd.to_datetime() の基本的な使い方から、format= の考え方、errors="coerce" の使いどころ、NaT の確認方法まで、初心者向けに順番に解説します。

この記事でわかること

  • pd.to_datetime() が必要になる場面
  • 文字列の日付列を datetime 型へ変換する基本手順
  • format=errors="coerce" の使い分け
  • NaT が出たときに何を確認すればよいか
  • 変換後にできる日付抽出・並び替え・月別集計の入口
  • astype()to_datetime() の違い

目次

  1. なぜ日付列を datetime 型に変える必要があるのか
  2. to_datetime() の基本と最初に覚える判断基準
  3. format= と errors=”coerce” を使った失敗しにくい変換手順
  4. to_datetime() と astype() の違い
  5. 変換後にできること
  6. よくある失敗例と対処
  7. 前処理の流れの中での位置づけ
  8. まとめ
  9. 関連記事
  10. FAQ

関連トピック

このテーマは、Pandasの前処理の流れの中では次の位置づけです。

DataFrame入門 → CSV読込 → 型確認 → 日付変換(今回) → 欠損対応 → 抽出・並び替え → 集計

あわせて読むと理解しやすい記事:

なぜ日付列を datetime 型に変える必要があるのか

CSVを読み込んだ直後は、日付列が文字列のままになっていることがあります。
見た目は日付でも、Pandasにとってはまだ「日付として使える列」ではありません。

たとえば、次のようなことをしたい場面です。

  • 2024年4月以降のデータだけ取り出したい
  • 日付順に並び替えたい
  • 月ごとの売上を集計したい

このような操作をするなら、まず日付列を datetime 型に変換するのが基本です。
つまり、この記事で最初に答えるべき問いへの答えは次のとおりです。

CSVで読み込んだ列を日付として比較・抽出・並び替え・集計したいなら、pd.to_datetime() に変換する意味があります。

文字列のままでも見た目は日付に見えますが、実際には扱い方がかなり変わります。

文字列のまま datetime型に変換後
文字列順で並んでしまうことがある 日付順で正しく並べやすい
月ごとの集計がしにくい 年・月・日を取り出して集計しやすい
条件抽出で書き方に迷いやすい 日付として自然に比較できる
欠損や異常値を見つけにくい NaT として確認しやすい

日付として比較・抽出・集計したいなら、最初に pd.to_datetime() で日時型に変えるのが基本です。

実際には、文字列のままだと「見た目は日付なのに、日付としては扱えない」という状態になりやすいです。

たとえば、日付列を文字列のまま並び替えると、期待した順番にならないことがあります。
まずは、文字列のまま並び替えた例を見てみましょう。

import pandas as pd

sort_df = pd.DataFrame({
    "注文日": ["2024-1-10", "2024-1-2", "2024-1-30"],
    "売上": [1200, 800, 1500]
})

sort_df.sort_values("注文日")
注文日売上
02024-1-101200
12024-1-2800
22024-1-301500

この結果は、文字列としての順番で並んでいます。
そのため、日付順に見たいときには不便です。

次に、pd.to_datetime() で変換してから並び替えてみます。

sort_df["注文日"] = pd.to_datetime(sort_df["注文日"])
sort_df.sort_values("注文日")
注文日売上
12024-01-02800
02024-01-101200
22024-01-301500

このように、datetime 型に変えておくと、日付として自然に並び替えや比較ができるようになります。

つまり pd.to_datetime() は、単なる変換ではなく、
「日付列を前処理の中で使える状態に整える処理」 と考えると分かりやすいです。

まずは、CSV読込後によくある状態を再現してみます。
ここでは StringIO を使って、Colab上でそのまま試せる小さなCSVデータを用意します。

※ ここでは説明用に StringIO を使っています。実務では pd.read_csv("ファイル名.csv") のように、CSVファイルを直接読むことが多いです。

import pandas as pd
from io import StringIO

csv_data = StringIO("""注文日,商品,売上
2024-04-01,りんご,1200
2024-04-03,みかん,900
2024-04-05,バナナ,1500
2024-05-01,ぶどう,1100
""")

orders_df = pd.read_csv(csv_data)
orders_df
注文日商品売上
02024-04-01りんご1200
12024-04-03みかん900
22024-04-05バナナ1500
32024-05-01ぶどう1100

orders_df注文日 は、見た目は日付でも、まだ文字列として扱われていることがあります。
型を確認してみましょう。

orders_df.dtypes
0
注文日object
商品object
売上int64

dtype: object

注文日object なら、まだ文字列です。
この状態で日付として使いたいなら、to_datetime() を検討します。

to_datetime() の基本と最初に覚える判断基準

初心者のうちは、次の判断基準を最初に持っておくと迷いにくいです。

  • 日付で比較・抽出・並び替え・集計したいなら to_datetime() を使う
  • 文字列の形式がそろっているなら format= を検討する
  • 変換エラーが気になるなら errors="coerce" で壊れた値を洗い出す
  • 汎用的な型変換は astype()、日付変換は to_datetime() と考える

まずは、いちばん基本の形です。

orders_df["注文日"] = pd.to_datetime(orders_df["注文日"])
orders_df.dtypes
0
注文日datetime64[ns]
商品object
売上int64

dtype: object

注文日datetime64[ns] になれば成功です。
これで 注文日 を「日付として使える列」に変えられました。

基本形は次の1行です。

df["日付列"] = pd.to_datetime(df["日付列"])

このように、変換した結果を列へ代入するのが基本です。

format= と errors=”coerce” を使った失敗しにくい変換手順

to_datetime() は、単に変換するだけでなく、形式を明示したり、変換できない値を見つけたりできるのが強みです。

format= を使うとき

文字列の日付形式がそろっているなら、format= を使うと意図がはっきりします。
たとえば、2024/04/01 のような形式なら、%Y/%m/%d を指定できます。

ここで迷いやすいのが、format= を書くべきかどうかです。

判断の目安は次の通りです。

  • 列の書式がそろっている → format= を指定しやすい
  • /- が混ざるなど、書式がばらついている → まず列の中身を確認する
  • 壊れた値や空欄が混ざっていそう → errors="coerce" で様子を見る

つまり、format= は「毎回必ず書くもの」ではなく、
書式がそろっている列を、安定して変換したいときに使う指定です。

sales_df = pd.DataFrame({
    "注文日": ["2024/04/01", "2024/04/03", "2024/04/05"],
    "商品": ["りんご", "みかん", "バナナ"],
    "売上": [1200, 900, 1500]
})

sales_df["注文日"] = pd.to_datetime(sales_df["注文日"], format="%Y/%m/%d")
sales_df
注文日商品売上
02024-04-01りんご1200
12024-04-03みかん900
22024-04-05バナナ1500

迷ったときは、次の順で考えると整理しやすいです。

  1. まず列の中身を見る
  2. 書式がそろっていれば format= を使う
  3. 壊れた値がありそうなら errors="coerce" で確認する

この順で考えると、format= を無理に書いて失敗することが減ります。

形式がそろっていると分かっている場合は、format= を使うことで「この形の日付として読む」という意図を明確にできます。

errors=”coerce” を使うとき

実務では、日付列に変換できない値が混ざることがあります。
そんなときに便利なのが errors="coerce" です。
変換できない値はエラーではなく NaT になります。

NaT は、datetime型における「欠損」のようなものです。

dirty_df = pd.DataFrame({
    "注文日": ["2024-04-01", "2024-04-31", "2024/05/02", "不明", None],
    "商品": ["りんご", "みかん", "バナナ", "ぶどう", "もも"],
    "売上": [1200, 900, 1500, 1100, 980]
})

dirty_df["注文日_変換後"] = pd.to_datetime(dirty_df["注文日"], errors="coerce")
dirty_df
注文日商品売上注文日_変換後
02024-04-01りんご12002024-04-01
12024-04-31みかん900NaT
22024/05/02バナナ1500NaT
3不明ぶどう1100NaT
4Noneもも980NaT

この例では、次のような値が NaT になる可能性があります。

  • 存在しない日付(例: 2024-04-31
  • 日付として読めない文字列(例: 不明
  • 欠損値(None

この使い方のよいところは、どの行が壊れているかをあとから確認しやすいことです。

NaT が出たあとに、どの行が欠損扱いになったかを確認したい場合は、
isnull() の使い方 もあわせて見ると流れがつかみやすいです。

dirty_df[dirty_df["注文日_変換後"].isna()]
注文日商品売上注文日_変換後
12024-04-31みかん900NaT
22024/05/02バナナ1500NaT
3不明ぶどう1100NaT
4Noneもも980NaT

変換に失敗した行だけを抜き出せるので、前処理の見直しがしやすくなります。

format= と errors=”coerce” はどう使い分けるか

初心者向けに整理すると、使い分けは次のように考えると分かりやすいです。

状況 まず考えたい書き方
形式がそろっている pd.to_datetime(..., format="...")
壊れた値が混ざるかもしれない pd.to_datetime(..., errors="coerce")
形式も怪しく、まず実態を見たい errors="coerce"NaT を確認してから整える

迷ったときは、最初に errors="coerce" で実態を把握し、その後に format= を詰める流れが安全です。

errors=”raise” はどんなときに使う?

errors="coerce" は、変換できない値を NaT にして処理を先へ進めたいときに便利です。
一方で、どの値が原因で変換に失敗したのかをその場で知りたいときは、errors="raise" を使います。

使い分けの目安は次の通りです。

指定 変換できない値があったとき 向いている場面
errors="coerce" NaT にする まず全体を確認したいとき
errors="raise" エラーで止まる 原因をその場で特定したいとき

初心者のうちは、まず coerce で全体を確認し、必要に応じて raise で原因を特定する流れが扱いやすいです。

test_df = pd.DataFrame({
    "注文日": ["2024-04-01", "2024-04-31", "2024-04-03"]
})

pd.to_datetime(test_df["注文日"], errors="raise")

このコードでは、存在しない日付 2024-04-31 が含まれているため、エラーになります。

つまり errors="raise" は、「変換を進める」より「原因を特定する」ための指定です。
反対に、いったん NaT にして後で確認したいときは errors="coerce" が向いています。

to_datetime() と astype() の違い

astype() も型変換の関数なので、「日付列も astype() でよいのでは?」と迷いやすいです。
ただし、初心者向けには次の整理が分かりやすいです。

観点 to_datetime() astype()
主な役割 日付・時刻への変換 汎用的な型変換
日付文字列への向き・不向き 日付変換に向いている 日付専用ではない
format= 指定 できる できない
errors="coerce" のような失敗値処理 できる できない
初心者が最初に使うべき場面 日付列を整えたいとき 数値型・文字列型などを変えたいとき

つまり、日付列を扱うなら to_datetime()、一般的な型変換なら astype() と考えると整理しやすいです。

数値や文字列の型変換をまとめて確認したい場合は、次の記事も役立ちます。
https://pythondatalab.com/pandas-astype/

迷ったら、日付列にはまず pd.to_datetime() を使うと覚えておくと大きく外しにくいです。

astype() は文字列・数値・整数・小数などの型変換でよく使いますが、
日付や時刻として扱いたい列では、to_datetime() を先に検討するのが基本です。

文字列・数値・整数・小数など、日付以外の型変換を整理したい場合は、
astype() の使い方 の記事もあわせて読むと違いがよりはっきりします。

変換後にできること

datetime 型に変えると、主にできることは次の3つです。

  • 日付で絞り込む
  • 日付順に並び替える
  • 月ごとに集計する

日付列を datetime 型に変える意味は、ここからはっきりしてきます。
まずは扱いやすいサンプルデータを用意します。

orders_df = pd.DataFrame({
    "注文日": ["2024-04-01", "2024-04-03", "2024-04-05", "2024-05-01", "2024-05-10"],
    "商品": ["りんご", "みかん", "バナナ", "ぶどう", "もも"],
    "売上": [1200, 900, 1500, 1100, 980]
})

orders_df["注文日"] = pd.to_datetime(orders_df["注文日"])
orders_df
注文日商品売上
02024-04-01りんご1200
12024-04-03みかん900
22024-04-05バナナ1500
32024-05-01ぶどう1100
42024-05-10もも980

日付で絞り込む

たとえば、2024年5月以降のデータだけを取り出すなら、次のように書けます。

orders_df[orders_df["注文日"] >= "2024-05-01"]
注文日商品売上
32024-05-01ぶどう1100
42024-05-10もも980

日付列を変換したあとに条件で絞り込む流れは、
pandas 条件抽出(filtering)入門 につながります。

日付順に並び替える

日付列が datetime 型なら、sort_values() でも自然に扱えます。

orders_df.sort_values("注文日", ascending=False)
注文日商品売上
42024-05-10もも980
32024-05-01ぶどう1100
22024-04-05バナナ1500
12024-04-03みかん900
02024-04-01りんご1200

日付順の並び替えをもう少し整理して学びたい場合は、
pandas 並び替え(sort)入門 も役立ちます。

月ごとに集計する

月別集計の入口として、dt.to_period("M") を使うと「月単位」にまとめやすくなります。

monthly_sales = (
    orders_df.groupby(orders_df["注文日"].dt.to_period("M"))["売上"]
    .sum()
    .reset_index()
)

monthly_sales
注文日売上
02024-043600
12024-052080

このように、to_datetime() は単なる変換で終わりません。
その後の抽出・並び替え・集計に進むための前処理として大事な役割があります。

条件抽出をもう少し整理して学びたい場合は、
pandas 条件抽出(filtering)入門 がつながります。

日付列を整えたあとに集計へ進みたい場合は、
Pandas groupby×aggの使い方 に進むと、前処理から集計への流れがつながります。

よくある失敗例と対処

ここでは、初心者がつまずきやすいポイントを3つに絞って整理します。

1. 形式が混在していて思った通りに変換できない

日付列の中に 2024-04-012024/04/02 のような形式の違いが混ざっていると、扱いにくくなることがあります。
まずは errors="coerce" で壊れる値を見つけると整理しやすいです。

mixed_df = pd.DataFrame({
    "注文日": ["2024-04-01", "2024/04/02", "2024-04-03", "2024/13/01"]
})

mixed_df["注文日_変換後"] = pd.to_datetime(mixed_df["注文日"], errors="coerce")
mixed_df
注文日注文日_変換後
02024-04-012024-04-01
12024/04/02NaT
22024-04-032024-04-03
32024/13/01NaT

形式がそろっていないときは、最初から厳密に format= を当てにいくより、
いったん NaT を確認してから、どの形式にそろえるか考えるほうが安全です。

形式が混在しているときは、すぐに複雑な処理を書くよりも、まず表記をそろえてから再変換するほうが分かりやすいです。

たとえば、/- が混ざっているだけなら、文字列を少し整えてから to_datetime() を使えます。

mixed_df["注文日_整形後"] = mixed_df["注文日"].str.replace("/", "-", regex=False)
mixed_df["注文日_変換後_再試行"] = pd.to_datetime(mixed_df["注文日_整形後"], errors="coerce")
mixed_df
注文日注文日_変換後注文日_整形後注文日_変換後_再試行
02024-04-012024-04-012024-04-012024-04-01
12024/04/02NaT2024-04-022024-04-02
22024-04-032024-04-032024-04-032024-04-03
32024/13/01NaT2024-13-01NaT

このように、確認 → 整形 → 再変換 の順で進めると、原因を切り分けやすくなります。

なお、整形しても NaT のまま残る値がある場合は、単なる記号の違いではなく、
存在しない日付や空欄などが含まれている可能性があります。

2. 存在しない日付が混ざっている

2024-04-31 のように、見た目は日付でも実在しない値は変換できません。
この場合も errors="coerce" を使えば、変換できない値だけが NaT になります。

invalid_df = pd.DataFrame({
    "注文日": ["2024-04-01", "2024-04-31", "2024-05-03"]
})

invalid_df["注文日_変換後"] = pd.to_datetime(invalid_df["注文日"], errors="coerce")
invalid_df
注文日注文日_変換後
02024-04-012024-04-01
12024-04-31NaT
22024-05-032024-05-03

存在しない日付は、表記ゆれではなく値そのものが正しくないため、整形だけでは直りません。
まず coerceNaT にして見つけ、元データを確認する流れが分かりやすいです。

「怪しい値を洗い出したい」ときは coerce
「その場でエラーにして原因を特定したい」ときは raise、と考えると整理しやすくなります。

3. 変換したのに反映されない

これはとても多いミスです。
pd.to_datetime(df["注文日"]) を実行しただけでは、元のDataFrameの列が自動で置き換わるとは限りません。

次のコードを見てみましょう。

check_df = pd.DataFrame({
    "注文日": ["2024-04-01", "2024-04-03", "2024-04-05"]
})

pd.to_datetime(check_df["注文日"])
check_df.dtypes
0
注文日object

dtype: object

この場合、pd.to_datetime(...) の結果は作られていますが、check_df["注文日"] に代入していないため、元の列の型は変わりません。

よくある書き方 結果
pd.to_datetime(check_df["注文日"]) 変換結果は作られるが、元の列は変わらない
check_df["注文日"] = pd.to_datetime(check_df["注文日"]) 元の列が datetime 型に変わる

反映されない理由

  • 変換結果を変数や列に代入していない
  • 元のDataFrameではなく、別のコピーを見ている
  • 変換後の列名を間違えて確認している

基本は次の形です。

df["注文日"] = pd.to_datetime(df["注文日"])

「実行したのに変わらない」と感じたら、まず dtypes を見て、本当に列型が変わったか確認するのがおすすめです。

前処理の流れの中での位置づけ

to_datetime() は、Pandas全体の流れの中では 前処理の一部 です。
位置づけを整理すると、次のようになります。

  1. CSVを読み込む
  2. head()info() で中身と型を確認する
  3. 数値列は astype()to_numeric()、日付列は to_datetime() で整える
  4. 必要なら isnull()fillna() で欠損対応する
  5. filtering や sort、groupby で分析する
  6. 必要ならグラフにする

この流れが見えていると、to_datetime() を単なる文法としてではなく、
「日付列を分析できる状態にするための処理」 として理解しやすくなります。

関連して読みやすい記事:

まとめ

pandas to_datetime() は、文字列の日付列を datetime 型へ変えるための基本機能です。
この記事では、初心者がまず押さえたいポイントを絞って見てきました。

  • 日付で扱いたい列なら、まず to_datetime() を検討する
  • 形式がそろっているなら format= を使うと意図が明確になる
  • 壊れた値を見つけたいなら errors="coerce" が便利
  • 原因をその場で特定したいなら errors="raise" も役立つ
  • NaT は datetime型における欠損のようなもの
  • datetime 型に変えると、日付抽出・並び替え・月別集計へ自然につなげやすい

大切なのは、to_datetime() を単なるAPIとして覚えるのではなく、
CSV読込後に日付列を分析しやすい形へ整える処理 として理解することです。

まずは df.info() で日付列が object のままになっていないか確認し、
文字列のままなら pd.to_datetime() を試してみましょう。

日付列を整えたあとに、実際に条件で絞り込む流れまで進めたい場合は、次に pandas 条件抽出(filtering)入門 を読むとつながりやすいです。

次に読みたい関連記事

次に読むなら、次の順番がおすすめです。

  1. Google Colab CSV 読み込み&保存入門|pandasでread_csvとto_csvを徹底解説
  2. Pandas info()とdescribe()の違い|欠損値・型・統計量の見方を例で解説
  3. pandas astype()の使い方|文字列・数値への型変換とエラー対処を初心者向けに解説
  4. pandas 条件抽出(filtering)入門|AND/OR・query関数・複数条件の指定方法
  5. pandas 並び替え(sort)入門|sort_values・sort_indexの違いと複数列ソート
  6. Pandas groupby×aggの使い方|基本の集計とaggの書き方を例で解説

▲ ページトップへ戻る

astype() と to_datetime() は何が違いますか?

astype() は汎用的な型変換、to_datetime() は日付変換向けの関数です。
日付列では format= や errors="coerce" を使える to_datetime() のほうが整理しやすいです。

to_datetime() で NaT が出るのはなぜですか?

変換できない文字列、存在しない日付、欠損値などがあると、errors="coerce" を使った場合に NaT になります。
まずは NaT になった行だけ抜き出して確認すると原因を見つけやすいです。

format= は毎回指定したほうがよいですか?

毎回必須ではありません。
ただし、文字列の形式がそろっていると分かっているなら、format= を指定したほうが意図が明確になりやすいです。

日付型に変えたあと、月別集計はどう始めればよいですか?

まずは df["日付列"].dt.to_period("M") を使って月単位にまとめ、groupby() と組み合わせると始めやすいです。
集計の考え方そのものは、groupby記事へ進むと理解が深まります。

pandas to_datetime() の format とは何ですか?

format= は、文字列の日付がどんな形で書かれているかを指定するための引数です。
たとえば 2024/04/01 のような形なら、format="%Y/%m/%d" のように書けます。
書式がそろっている列では、format= を指定したほうが変換の意図がはっきりしやすくなります。

pandas to_datetime() の errors=”coerce” とは何ですか

errors="coerce" を指定すると、変換できない値をエラーにせず NaT にします。
そのため、処理を止めずに、
「どの行が日付として正しく読めなかったか」を後から確認したいときに便利です。

read_csv() の parse_dates と to_datetime() はどう違いますか?

parse_dates は、CSVを読み込む時点で日付列を日時型として読み込みたいときに使います。
一方、pd.to_datetime() は、読み込んだあとで日付列を変換したいときに使います。
まずはCSV読込後に列の状態を確認しながら進めたい初心者には、
あとから pd.to_datetime() を使う流れのほうが理解しやすいことが多いです。

コメント

タイトルとURLをコピーしました