Claudeでデジタコの運行記録を分析する手順 — 速度超過・急ブレーキ・連続運転
デジタコの運行記録CSVをFiles APIで渡し、コード実行ツールに速度超過・急ブレーキ・連続運転を集計させ、手元のスクリプトで突き合わせて運転者別の指導対象を出す手順です。
Claudeでデジタコの運行記録を分析する手順 — 速度超過・急ブレーキ・連続運転
デジタルタコグラフ(デジタコ)の運行記録は、数秒から数十秒おきの速度が並ぶ長いCSVになります。運転者が数人でも数万行です。ここから速度超過、急ブレーキ、連続運転を拾って指導面談の材料にする作業を、Claudeのコード実行ツールに任せる手順をまとめます。
流れは3段です。CSVをFiles APIでアップロードし、集計をコード実行ツールにPythonで走らせ、同じ規則の手元スクリプトで結果を突き合わせます。拘束時間と休息期間の告示照合はClaudeで改善基準告示に拘束時間を照合するの領分で、ここでは扱いません。
何を抽出するかを先に決める
デジタコのCSVは、メーカーと機種によって列名も記録間隔も違います。それでも指導対象を出すだけなら、運転者、時刻、速度の3列があれば足ります。位置や距離の列は、急ブレーキの原因を現場で聞くときに役立ちますが、集計そのものには要りません。
この記事では、次の3列だけのCSVを例にします。データは本記事のために作った架空のもので、3人の運転者、10秒間隔、合計6,474行です。実際の機種では、先頭数行をClaudeに見せて列の対応を伝えれば足ります。
driver_id,timestamp,speed_kmh
D01,2026-10-05 06:00:00,11
D01,2026-10-05 06:00:10,21
D01,2026-10-05 06:00:20,363つの指標の定義は、次のように置きます。
| 指標 | この記事での判定 | しきい値の出どころ |
|---|---|---|
| 速度超過 | この記事での判定速度が90km/hを超えたサンプル | しきい値の出どころ社内基準の仮置き |
| 急ブレーキ | この記事での判定1サンプル(10秒)で速度が20km/h以上落ちた | しきい値の出どころ社内基準の仮置き |
| 連続運転 | この記事での判定運転の中断を挟まず4時間を超えた走行 | しきい値の出どころ改善基準告示 |
速度超過と急ブレーキの数値は、会社が決める指導基準です。トラック運転者向けの厚生労働省のテキストには、この2つの数値の定めは載っていません。道路の種別が列にないため、速度超過は一律の値で数えます。高速道路と一般道で上限を分けたい場合は、位置情報や道路種別の列を足し、規則に書き加えます。
連続運転だけは告示に根拠があります。同テキストによると、連続運転時間は4時間以内で、運転開始後4時間以内または4時間経過直後に30分以上の運転の中断が必要です。中断は1回おおむね連続10分以上とした上で分割でき、10分未満の中断は3回以上連続しない扱いです。
CSVをアップロードしてコード実行に集計させる
コード実行ツールは、サンドボックスのコンテナでPythonとBashを動かします。Python 3.11で、pandasやnumpyが入っています。インターネットには接続できないので、実行時にパッケージは追加できません。今回の集計はpandasだけで済みます。
CSVは、プロンプトに貼らずFiles APIでアップロードし、container_upload ブロックで渡します。数万行を貼ると入力トークンを食うだけでなく、行の数え間違いも起きます。貼り付けとアップロードの正答率と費用の差はFiles APIとcode executionでCSVを集計するに実測があります。
import anthropic
from pathlib import Path
client = anthropic.Anthropic()
f = client.files.upload(file=Path("tacho.csv"))
rules = """デジタコの運行記録CSV(driver_id, timestamp, speed_kmh。10秒間隔)を
運転者ごとに集計してください。計算は必ずコード実行ツールで行い、暗算しないでください。
- 速度超過: speed_kmh が 90 を超えたサンプルの数と最高速度
- 急ブレーキ: 直前のサンプルより 20km/h 以上速度が落ちた時刻の一覧
- 連続運転: 速度0が10分以上続いた区間を運転の中断とし、中断の合計が
30分に達したら連続運転をリセットする。リセットなしで走った最長時間
- 結果は運転者ごとの表にし、指導対象の理由を添える
- 最後に実行したコードを添える"""
response = client.messages.create(
model="claude-opus-5-5",
max_tokens=4096,
messages=[{"role": "user", "content": [
{"type": "text", "text": rules},
{"type": "container_upload", "file_id": f.id},
]}],
tools=[{"type": "code_execution_20250825", "name": "code_execution"}],
)
print(response.to_json())規則をプロンプトに書くのは、判定の前提を毎回同じにするためです。しきい値が変われば、その数字だけ書き換えます。Claudeに「急ブレーキを探して」とだけ頼むと、どの速度低下を急とみなすかが回答ごとにぶれます。
簡単な算術はツールを使わずに答えることがあるため、計算を確実に回したいときは「コード実行ツールで行う」と明記します。
手元のスクリプトで同じ集計を回す
Claudeの返した表をそのまま指導の根拠にせず、同じ規則を実装したスクリプトに同じCSVを通します。2つの数字が一致すれば、規則の解釈と集計の両方が合っていると見てよい状態になります。pandas 3.0.6、Python 3.12で動かしたスクリプトは次のとおりです。
import pandas as pd
LIMIT = 90 # 社内の速度超過基準(km/h)
BRAKE_DROP = 20 # 急ブレーキ: 1サンプルで落ちた速度(km/h)
MIN_BREAK = 10 # 運転の中断として数える停車(分)
STEP = 10 # サンプル間隔(秒)
df = pd.read_csv("tacho.csv", parse_dates=["timestamp"])
df = df.sort_values(["driver_id", "timestamp"])
out = []
for d, g in df.groupby("driver_id"):
g = g.reset_index(drop=True)
drop = g.speed_kmh.shift(1) - g.speed_kmh
stopped = g.speed_kmh.eq(0)
run_id = (stopped != stopped.shift()).cumsum()
drive_s, brk_s, worst = 0, 0, 0
for _, seg in g.groupby(run_id):
secs = len(seg) * STEP
if seg.speed_kmh.iloc[0] == 0:
if secs >= MIN_BREAK * 60:
brk_s += secs
if brk_s >= 30 * 60: # 中断が合計30分で打ち切り
drive_s, brk_s = 0, 0
else:
drive_s += secs
worst = max(worst, drive_s)
out.append(dict(driver=d, over_cnt=int((g.speed_kmh > LIMIT).sum()),
max_speed=g.speed_kmh.max(),
hard_brake=int((drop >= BRAKE_DROP).sum()),
longest_drive_h=round(worst / 3600, 2)))
res = pd.DataFrame(out)
res["flag"] = res.apply(lambda r: ",".join(
[x for x, c in [("速度超過", r.over_cnt > 0),
("急ブレーキ", r.hard_brake > 0),
("連続運転4h超", r.longest_drive_h > 4)] if c]) or "-",
axis=1)
print(res.to_string(index=False))
# 面談で見せる根拠として、急ブレーキの時刻も出す
for d, g in df.groupby("driver_id"):
drop = g.speed_kmh.shift(1) - g.speed_kmh
for _, r in g[drop >= BRAKE_DROP].iterrows():
print(d, r.timestamp, f"{int(r.speed_kmh + drop[r.name])}->{r.speed_kmh}km/h")上のCSVで実行した出力です。
driver over_cnt max_speed hard_brake longest_drive_h flag
D01 12 98 3 5.0 速度超過,急ブレーキ,連続運転4h超
D02 0 69 0 5.0 連続運転4h超
D03 0 75 0 2.0 -
D01 2026-10-05 06:18:40 98->70km/h
D01 2026-10-05 09:20:00 70->17km/h
D01 2026-10-05 10:26:40 66->17km/h3人の結果から指導対象を読む
D03は3項目とも該当がなく、最長の連続運転は2.0時間です。指導の対象はD01とD02になります。
D01は速度超過が12サンプルで、最高速度は98km/hです。10秒間隔なので、おおよそ2分間、90km/hを超え続けた計算になります。急ブレーキの3件のうち、9時20分と10時26分の2件は70km/hや66km/hから17km/hへの減速で、面談で場面を聞く価値があります。
残る1件の6時18分は、98km/hから70km/hへの減速です。これは速度超過が終わって通常の速度に戻った瞬間で、急ブレーキとは限りません。しきい値だけで数えると、こうした減速も拾います。件数だけで評価せず、時刻の一覧を運転者に見せて場面を確かめる運用にすれば、誤検出で指導が空回りするのを避けられます。
D02は速度も減速も問題ない一方、連続運転が5.0時間です。8分の停車を3回挟んで走っていて、1回10分未満の中断が3回続いたため、告示の「10分未満の中断は3回以上連続しない」に当たる形です。合計では24分の停車がありますが、10分未満の停車は中断として数えません。面談では、停車の回数と1回ごとの長さを時刻つきで示します。
D01も連続運転が5.0時間です。こちらは停車なしで5時間走ったあとに30分停車しているため、4時間を超えた時点で該当します。
連続運転の数え方を規則に入れる
連続運転は、速度の列だけでは単純に判定できません。数え方を3点、規則に書いておきます。
1点目は、中断の最小単位です。トラック運転者向けのテキストは、運転の中断を1回おおむね連続10分以上としています。2回の停車が合計30分でも、1回9分の停車は中断に入りません。スクリプトの MIN_BREAK がこの10分に当たります。
2点目は、リセットの条件です。中断が合計30分に達したら連続運転をゼロに戻します。テキストの例では、20分と10分の中断を挟んだ走行も基準を満たします。スクリプトでは brk_s を足し込み、30分で drive_s を戻しています。
3点目は、停車が休憩とは限らないことです。荷待ちや荷役で速度0が続いた時間も、CSVの上では停車に見えます。テキストは、運転の中断時には原則として休憩を与えるとしていますが、CSVから休憩かどうかまでは分かりません。休憩なのか荷役なのかは、運転日報や運行指示書と照らして決めます。
テキストには、サービスエリアやパーキングエリアなどに駐停車できずやむを得ない場合に4時間30分まで延長できる例外もあります。位置の列がないCSVではこの例外を判定できないため、4時間超の連続運転は「確認対象」として拾い、延長が認められる状況かどうかは人が見ます。
突き合わせで食い違ったときの見方
Claudeの表と手元の出力が食い違ったら、まず件数を比べます。速度超過の件数がずれるなら、「90を超える」を「90以上」と読んでいないかを疑います。急ブレーキの件数がずれるなら、速度低下を見る基準が1サンプル前との差か、数サンプルにまたがる差かが違っている可能性があります。
連続運転の時間がずれたときは、規則の書き方が原因のことが多くなります。10分未満の停車を中断に数えたか、中断の合計30分でリセットしたか、の2点です。Claudeが返したコードを読んで、どの行で判定が分かれたかを見つけ、規則の文を直してやり直します。食い違いの原因が規則の曖昧さなら、直した文を次回以降もそのまま使えます。
運転者のデータを送る前に決めること
運行記録は、運転者ごとの走り方が分かるデータです。コード実行ツールとFiles APIに送る前に、次の点を決めておきます。
- 運転者名は伏せ、社内の運転者コードに置き換えてから送る。対応表は社内に残す
- コード実行ツールの仕様ページは、ZDR(ゼロデータリテンション)の対象外と記載している。Files APIのページも同じ記載
- コンテナのデータ(アップロードしたファイルと出力を含む)は最大30日保持される
- Files APIにアップロードしたファイルは、削除するか
expires_atに達するまで残る。アップロード時にexpires_in_secondsを付ければ自動で期限を設定できる - 集計が済んだら
DELETE /v1/files/{file_id}で削除する。削除したファイルは復元できない
アップロード済みの file_id の扱いはClaude Files APIのfile_idセキュリティリスクと対策にまとめています。
料金と実行環境の上限
コード実行ツールは、Web検索やWeb Fetchと併用しない場合、実行時間で課金されます。実行時間は最低5分で、組織ごとに月1,550時間までは無料です。超えた分は1コンテナあたり1時間0.05ドルです。ファイルを付けたリクエストは、ツールが呼ばれなくても、ファイルがコンテナに先読みされる分の実行時間が課金されます。
運行記録の集計は1回数分で終わる想定なので、月1,550時間を使い切る心配は小さいでしょう。無料になる条件の詳細はコード実行ツールが無料になる条件にあります。
コンテナのメモリは5GiB、ディスクは5GiB、CPUは1つです。ファイルが大きいときは、運転者ごとや週ごとに分けて送れば、この範囲に収まりやすくなります。
この集計が判定しない範囲
この手順で出るのは、指導面談を始めるための候補です。違反や過失の認定ではありません。
- 速度超過のしきい値は一律なので、道路ごとの制限速度は反映していない
- 急ブレーキは速度の落ち方だけで見ており、前方の危険回避だったかどうかは分からない
- 連続運転の停車が休憩か荷役かは、CSVからは区別できない
- 拘束時間、休息期間、運転時間の基準は対象外
しきい値は、最初は緩めに置いて該当を絞り、面談で「この数字は妥当だった」と確かめられたものから厳しくするほうが運用が続きます。
まとめ
デジタコのCSVから指導対象を出すには、しきい値と連続運転の数え方を規則として文章にし、集計をコード実行ツールに任せ、手元のスクリプトで同じ数字が出るか突き合わせます。今回の例では、速度超過と急ブレーキはD01、停車を細切れに挟んだ連続運転はD02が対象になり、誤検出に近い減速も時刻の一覧で見分けられました。運転者データを外部に送る以上、運転者のコード化と削除の期限はアップロード前に決めておきます。