データ分析やAIモデルの開発を外部に委託する場面が増えています。社内に専門人材が少ない場合、外注は現実的で合理的な選択肢です。一方で、納品後に「なぜこの予測値になるのか説明できない」「契約が終わったら更新の方法が分からない」「小さな変更でも外注先に依頼しないとできない」といった状況に直面する企業は少なくありません。
こうした状況を受けて「最初から内製化すべきだった」と考えるのは自然な発想です。内製化は有力な選択肢ですが、人材の確保や育成には時間がかかり、すべての分析を社内に切り替えられるとは限りません。外注か内製かを先に決めようとすると、かえって判断が止まってしまうことがあります。
最初に決めたいのは、外注するか内製するかではなく、「外注しても、社内が説明・再実行・更新判断できる状態を残せているか」です。この状態は、社員が分析を自作できることとは別のものです。
本記事では、ブラックボックス化が起きる構造、社内に残すべき3つの資産(データ定義・分析ロジック・再現手順)と更新判断、汎用のサンプルコード、契約時・開発中・納品時の確認項目を整理します。
なぜ、外注した分析やモデルはブラックボックス化するのか
分析を外部に委託すると、発注側に届くのは多くの場合「結果」です。予測値、集計表、報告書、精度の報告値などがこれにあたります。一方で、結果に至るまでの「過程」、つまりデータの抽出条件、加工の方法、分析ロジック、試行錯誤の経緯、実行環境は、外注先の作業環境に残りやすい構造があります。
これは、外注先が情報を隠しているという意味ではありません。発注時に「結果」を仕様として定め、「過程を記録して納品すること」が仕様に含まれていなければ、記録は成果物として整備されないまま終わりやすいためです。ブラックボックス化は、悪意よりも、納品物の定義の抜けから生じやすい現象といえます。
ブラックボックス化が起きる構造(概念図)
結果は社内に渡り、過程は外注先の環境に残りやすい
発注側(社内)に渡るもの
- 予測値・集計結果
- 報告書・画面
- 外注先が報告する精度
外注先の環境に残りやすいもの
- データの抽出・加工の条件
- 分析ロジックと試行錯誤の経緯
- 実行環境とライブラリのバージョン
- 実行の順番と作業ファイル
概念図であり、外注先が情報を意図的に隠すことを意味するものではありません。納品物の定義に過程が含まれていない場合に起きやすい構造を示しています。
ここで、混同されやすい二つを切り分けておきます。ブラックボックス化は「中身が社内から見えない状態」を指し、委託依存は「変更や判断のたびに外注先が必要になる状態」を指します。中身が見えない状態が続くと、変更や判断を自社で行えなくなり、ベンダーロックイン(Vendor lock-in:特定の外注先への依存により、切り替えや内製化が難しくなる状態)につながる場合があります。
ブラックボックス化が進みやすい要因として、次の3点が挙げられます。
- 納品物が、予測値やレポートなど結果中心で定義されている
- 過程の記録が、外注先の作業ファイルの中にしか存在しない
- 社内の窓口や外注先の担当者が交代し、経緯を知る人がいなくなる
仮想例:需要予測モデルの契約終了後に起きること
以下は説明用の仮想例であり、実在の事例ではありません。小売業の企業が需要予測モデルを外注し、一定期間は問題なく運用できていたとします。契約終了から数か月後、予測と実績の乖離(かいり)が目立つようになりましたが、モデルをどう更新すればよいのか、社内の誰も把握していませんでした。
原因を分解すると、欠けていたのはモデルそのものではなく、モデルを説明し、動かし、見直すための周辺の記録でした。症状、欠けていた資産、本来あるべき成果物の対応を表にまとめます。
| 症状 | 欠けていた資産 | 本来あるべき成果物 |
|---|---|---|
| 「売上金額」が税込か税抜か、返品を控除しているかが分からない | データ定義 | データ定義書 |
| 販促の有無や気温などを、どう加工して使っていたかが外注先の作業ファイルにしかない | 分析ロジック | 分析ロジック記録 |
| 抽出条件(SQL)、実行環境、ライブラリのバージョン、実行の順番が残っておらず、同じ結果を出せない | 再現手順 | 再現手順書、実行記録 |
| どの指標で監視し、どの水準で見直すかが決まっておらず、乖離が出ても判断できない | 更新判断 | 更新判断のルール |
現実には、似た形の問題がほかにも起こります。たとえば、外注先の担当者が交代して説明の内容が変わり、どれが正しいのか判断できなくなる場合があります。また、コード一式は受け取ったものの、実行に必要なデータが手元になく、動かせない場合もあります。コードがあることと、再実行できることは別です。
ただし、この例から結論を一般化することはできません。同じような状況でも、契約内容や体制によって原因は異なります。また、外注先だけの問題とは限らず、発注側が納品物として求めていなかったために記録が残らなかったケースも少なくありません。
「外注か内製か」ではなく、社内に残す3つの到達レベル
社内が持つべき状態を、次の3段階で整理します。
| 到達レベル | 社内ができる状態 | 必要な成果物 | 社内の役割 |
|---|---|---|---|
| レベル1:説明できる | 分析の目的、使うデータの意味、結果の読み方を、社内の言葉で説明できる | データ定義書、分析ロジック記録 | 事業部門が目的と指標の意味を、情報システム担当がデータの出どころを説明できるよう確認する |
| レベル2:再実行できる | 手順書に従い、社内の担当者が同じ入力から同じ出力を得られる | 再現手順書、実行記録、実行環境の情報 | DX推進担当や情報システム担当が再実行テストを行う |
| レベル3:更新判断できる | 見直しの要否、時期、範囲を社内で判断し、依頼内容を決められる | 更新判断のルール、監視指標、見直しの履歴 | 事業部長や経営層が見直しを判断し、実務担当が指標を確認する |
ここでいう「社内に残す」とは、社員が分析を自作できることを意味しません。説明・再実行・更新判断ができる状態を指します。分析の実装や手法の選定を外注先に任せ続けていても、この3つが社内でできれば、外注先を主体的に管理でき、必要に応じて切り替えることもできます。
ただし、すべての案件でレベル3まで目指す必要があるという意味ではありません。業務への影響が小さい分析であれば、レベル1にとどめる判断もあり得ます。重要なのは、案件ごとに目標とするレベルを決めたうえで外注することです。
社内に残すべき3つの資産とは何か
3つのレベルを支えるのが、データ定義・分析ロジック・再現手順という3つの資産です。更新判断は、この3つが揃っていることを前提に成り立ちます。
社内に残すべき3つの資産と、その上に載る更新判断(概念図)
下の資産が揃うほど、上の判断を社内で行いやすくなる
この数字は、何を指しているのか
成果物:データ定義書
どの情報を、なぜ、どう加工して使っているのか
成果物:分析ロジック記録
別の担当者が、同じ結果を出せるのか
成果物:再現手順書、実行記録
概念図であり、3つの資産を揃えれば将来の精度が維持されることを意味するものではありません。
資産1:データ定義
データ定義は、各列が何を指すかの記録です。含めたい項目は、意味、型、単位、粒度(日次か月次か、店舗別か全社か)、欠損時の扱い、出どころ、責任部署です。同じ「売上金額」という列名でも、税込か税抜か、返品を控除するかどうかで意味が変わります。責任部署が決まっていないと、定義が変わったときに誰にも伝わらず、分析結果だけが静かにずれていくおそれがあります。
資産2:分析ロジック
分析ロジックは、何を目的に、どの情報をどう加工し、どの指標で評価したかの記録です。コードは「何をしたか」を示しますが、「なぜそうしたか」までは書かれません。ロジック記録には、目的、使った情報と加工の内容、除外した条件、評価指標、前提、既知の限界を、事業側が読める言葉で書きます。数式をすべて書き写す必要はありません。ただし、これは技術的な詳細が不要という意味ではなく、詳細はコードや設計書に委ね、ロジック記録は両者を結びつける役割を持つということです。
資産3:再現手順
再現手順は、同じ入力から同じ出力を得るための手順です。データの抽出条件(SQL:データベースから条件を指定してデータを取り出すための言語で書かれた命令文)、実行環境、ライブラリのバージョン、実行の順番を含めます。再現手順書の目次は、たとえば次のような構成が考えられます。
- 環境準備(実行環境、ライブラリのバージョン)
- データ取得(抽出条件、取得元、期間)
- 前処理(加工の内容と順番)
- 学習(使用する列、主要なパラメータ、乱数シード)
- 評価(評価指標、評価期間)
- 出力(出力先、形式)
- 確認(結果が一致しているかの確認方法)
サンプルコードで見る、残し方の具体例
ここでは、3つの資産を具体化する汎用のサンプルを示します。データはすべて架空で、列は date、store_id、item_category、sales_qty、sales_amount、price、promo_flag、temperature を想定します。モデルの種類は特定せず「任意の予測モデル」とします。コードを読み飛ばす場合は、各例の前後にある「社内に何が残るか」の説明だけでも要点が分かります。
例1:データ定義書(YAML)
この定義書によって社内に残るのは、列の意味、単位、粒度、許容される値、欠損時の扱い、責任部署です。担当者が交代しても、「売上金額」の解釈を同じに保てるようになります。
# 説明用の架空のデータ定義書(数値は仮置き。実際は業務に合わせて社内で決める)
dataset: daily_sales
description: 店舗別・商品カテゴリ別の日次売上(架空のサンプル)
granularity: 日次 x 店舗 x 商品カテゴリ
owner_department: 営業企画部
source_system: 販売管理システム(日次バッチで抽出)
columns:
date:
type: date
description: 売上計上日
max_missing_rate: 0.0
store_id:
type: string
description: 店舗を識別するコード
max_missing_rate: 0.0
item_category:
type: string
description: 商品カテゴリ
max_missing_rate: 0.0
sales_qty:
type: int
unit: 個
description: 販売数量(返品分を差し引いた数量)
max_missing_rate: 0.0
sales_amount:
type: float
unit: 円
description: 税抜・返品控除後の売上金額
max_missing_rate: 0.0
missing_handling: 補完せず、抽出元の担当部署へ確認する
price:
type: float
unit: 円
description: 税抜の販売単価
min: 0
max_missing_rate: 0.0
promo_flag:
type: int
description: チラシ掲載または値引き実施の日を1、それ以外を0
allowed_values: [0, 1]
max_missing_rate: 0.0
temperature:
type: float
unit: ℃
description: 店舗最寄りの観測地点の日平均気温
source_system: 外部の気象データ
min: -30
max: 45
max_missing_rate: 0.01
missing_handling: 補完した場合は日数を実行記録に残すYAML表計算ソフトの表で管理しても構いません。形式よりも、内容を承認する人と責任部署が決まっていることが重要です。
例2:入力データのチェックスクリプト(Python)
このコードによって社内に残るのは、「どのようなデータであれば実行してよいか」という条件です。納品後に新しいデータを入れるとき、定義との違いを実行前に検知できます。
# 入力データをデータ定義書と照合するチェック(汎用サンプル)
import pandas as pd
import yaml
TYPE_CHECKS = {
"date": pd.api.types.is_datetime64_any_dtype,
"string": lambda s: pd.api.types.is_string_dtype(s) or pd.api.types.is_object_dtype(s),
"int": pd.api.types.is_integer_dtype,
"float": pd.api.types.is_numeric_dtype,
}
def check_input(df: pd.DataFrame, spec_path: str) -> list[str]:
with open(spec_path, encoding="utf-8") as f:
spec = yaml.safe_load(f)
warnings = []
for name, rule in spec["columns"].items():
if name not in df.columns:
warnings.append(f"[列なし] {name}")
continue
s = df[name]
if not TYPE_CHECKS[rule["type"]](s):
warnings.append(f"[型の不一致] {name}: 定義={rule['type']} / 実際={s.dtype}")
missing_rate = s.isna().mean()
if missing_rate > rule.get("max_missing_rate", 0.0):
warnings.append(f"[欠損率] {name}: {missing_rate:.2%}")
values = s.dropna()
if "min" in rule and (values < rule["min"]).any():
warnings.append(f"[下限を下回る値] {name}")
if "max" in rule and (values > rule["max"]).any():
warnings.append(f"[上限を上回る値] {name}")
if "allowed_values" in rule and not values.isin(rule["allowed_values"]).all():
warnings.append(f"[許容値以外] {name}")
extra = set(df.columns) - set(spec["columns"])
if extra:
warnings.append(f"[定義にない列] {sorted(extra)}")
return warnings
if __name__ == "__main__":
df = pd.read_csv("sample_sales.csv", parse_dates=["date"])
for message in check_input(df, "data_definition.yaml"):
print("警告:", message)Python警告が出たときに処理を止めるのか、確認のうえで続行するのかも、運用ルールとして決めておく必要があります。なお、警告が出ないことは、データが正しいことの保証にはなりません。
例3:実行記録(メタデータ)のJSON保存
この記録によって社内に残るのは、「どのデータ、どの設定、どの環境で出した結果か」という履歴です。精度が変化したときに、データが変わったのか、設定が変わったのかを切り分ける手がかりになります。
# 実行記録をJSONで保存するサンプル(汎用)
import hashlib
import json
import platform
from datetime import datetime, timezone
from importlib.metadata import version
def sha256_of_file(path: str) -> str:
h = hashlib.sha256()
with open(path, "rb") as f:
for chunk in iter(lambda: f.read(1024 * 1024), b""):
h.update(chunk)
return h.hexdigest()
def save_run_record(df, data_path, used_columns, params, metrics, seed, out_path):
record = {
"run_at": datetime.now(timezone.utc).isoformat(),
"data_period": f"{df['date'].min():%Y-%m-%d}〜{df['date'].max():%Y-%m-%d}",
"row_count": int(len(df)),
"data_sha256": sha256_of_file(data_path),
"used_columns": used_columns,
"parameters": params,
"metrics": metrics,
"random_seed": seed,
"python": platform.python_version(),
# 実際に使うモデル関連のライブラリも同様に追記する
"libraries": {"pandas": version("pandas")},
}
with open(out_path, "w", encoding="utf-8") as f:
json.dump(record, f, ensure_ascii=False, indent=2)
return recordPython出力される記録のイメージを、架空の値で示します。
{
"run_at": "2025-04-01T00:00:00+00:00",
"data_period": "2023-04-01〜2025-03-31",
"row_count": 128400,
"data_sha256": "(ファイルから計算した値)",
"used_columns": ["date", "store_id", "item_category", "sales_qty",
"sales_amount", "price", "promo_flag", "temperature"],
"parameters": {"model": "任意の予測モデル", "forecast_horizon_days": 14},
"metrics": {"metric": "MAPE", "value": null},
"random_seed": 42,
"python": "(実行時のバージョン)",
"libraries": {"pandas": "(実行時のバージョン)"}
}JSONハッシュ値(Hash value:ファイルの内容から計算する固定長の識別値で、内容が変わると値も変わる)は、同じデータかどうかの確認に使えます。MAPE(Mean Absolute Percentage Error:平均絶対パーセント誤差)は、予測の誤差割合を見る指標の一つです。用途によっては別の指標が適する場合もあるため、何を採用するかは分析ロジック記録に理由とともに残します。評価の値は架空例のため省略しています。
この3つの例に共通するのは、「定義書と照合する」「実行のたびに記録する」という二点です。実行記録があっても、将来の精度が保証されるわけではありません。あくまで、変化の原因を調べるための手がかりです。
外注先に任せてよいこと、社内が持つべきこと
すべてを社内に持ち帰る必要はありません。分けて考えると、次のようになります。
| 項目 | 外注先に任せてよいこと | 社内が持つべきこと |
|---|---|---|
| データの意味 | 定義書の初版ドラフトの作成支援 | 定義の確定と承認、責任部署の明記 |
| 分析ロジック | 手法の選定、実装、試行 | 目的・評価指標・採用理由の理解と、記録の保管 |
| 実行環境と手順 | 環境構築、実行の自動化 | 環境情報の保管、再実行できる権限と手順 |
| 精度の監視 | 監視の仕組みの実装支援 | 監視指標の決定、見直しの判断 |
| 成果物の保管 | 納品物の作成 | 保管場所、アクセス権限、引き継ぎ先の管理 |
この表は一例であり、任せてよい範囲は案件の重要度、社内体制、契約内容によって異なります。どの項目を社内に置くかは、「その判断を外注先なしで行えないと困るか」を基準に考えると整理しやすくなります。
更新判断のルールはどう決めるか
ここで、もう一つ切り分けておくべき点があります。「再現できる」と「将来も同じ精度が出る」は別のことです。再現性とは、過去の結果を同じ条件で再び得られることを指します。一方、将来の精度は、販促方法、商品構成、店舗の状況などデータの傾向が変わることで低下する場合があります。再現手順が整っていても、見直しが不要になるわけではありません。
更新判断のルールには、次の4点を含めることが考えられます。
- 監視指標:何の指標で精度を見るか
- 比較対象:納品時の水準や、単純な前年同期の値などと比べるか
- 見直しを検討する条件:どの程度の乖離や、どの業務上の変化で見直すか
- 担当と手順:誰が確認し、誰が判断し、誰に依頼するか
具体的な水準や頻度は、業務の変化の速さ、予測の用途、誤差が事業に与える影響によって変わるため、本記事では数値を示しません。また、「見直さない」「今は更新しない」という判断も一つの選択肢です。その場合は、判断の理由と確認日を記録しておくと、後から経緯を追えます。
契約時・開発中・納品時に何を確認するか
資産は、納品時に慌てて集めるより、契約の段階から納品物として定義しておくほうが確実です。時期ごとの確認項目を表にまとめます。
| 時期 | 確認項目 | 確認できている状態 |
|---|---|---|
| 契約時 | 納品物の範囲 | 結果だけでなく、データ定義書・分析ロジック記録・再現手順書・実行記録が納品物に明記されている |
| 契約時 | 成果物の帰属と利用範囲 | コード、モデル、中間データの取り扱いが整理され、法務部門などで確認されている |
| 契約時 | 担当者交代時の対応 | 交代時に説明と記録を更新することが取り決められている |
| 契約時 | 契約終了後の問い合わせ | 終了後の質問対応や追加支援の可否・条件を確認している |
| 開発中 | 定期レビューでの説明 | データの扱いと加工の理由を社内担当者が質問し、記録に反映している |
| 開発中 | データ定義の早期確定 | 主要な列の意味を、初期の段階で社内が確認し承認している |
| 開発中 | 環境情報の記録 | 実行環境、ライブラリのバージョン、乱数シードが開発中から記録されている |
| 納品時 | 再実行テスト | 社内メンバーが手順書に従って再実行し、結果の一致を確認している |
| 納品時 | 入力データのチェック | データ定義書との照合を、社内で実行できる |
| 納品時 | 更新判断のルール | 監視指標、見直しの条件、担当者が文書化されている |
| 納品時 | 保管と権限 | 納品物の保管場所、閲覧・実行の権限、引き継ぎ先が決まっている |
納品時の「社内メンバーによる再実行テスト」は、次の手順で進めると形骸化しにくくなります。
- 開発に関わっていない社内メンバーを実行者に指名する
- 再現手順書だけを渡し、口頭での補足は行わない。補足が必要になった点は、手順書に追記する
- 納品時点のデータと実行環境で再実行する
- 実行記録を出力し、納品された結果と一致するかを確認する。一致の基準(完全一致か、許容する差か)は事前に決めておく
- 詰まった点を一覧にして、外注先とともに手順書へ反映する
乱数の扱いや実行環境の差により、結果が完全には一致しない場合もあります。そのため、許容する差を事前に合意しておくことが大切です。
成果物の帰属や利用範囲など、契約・知的財産に関わる論点は、案件ごとに判断が分かれます。一般的な論点を整理した資料として、経済産業省の「AI・データの利用に関する契約ガイドライン」があります。最新版の内容を確認したうえで、具体的な契約条項については法務部門や専門家にご相談ください。
今日から始める、既存案件の簡易確認
すでに外注している案件がある場合は、すべてを整備してから始める必要はありません。まず、業務への影響が大きい案件を1件選び、次の3つに答えられるかを確認します。
- 入力データの主要な列を3つ選び、それぞれの意味(単位や、税込・税抜などの条件)を一文で書けるか
- 再現手順書が存在し、開発に関わっていない担当者がその手順で実行できそうか
- 精度を見る指標と、見直しを検討する条件が決まっているか
答えられなかった項目が、その案件で社内に残っていない資産です。そこから、外注先への問い合わせや、記録の追加依頼の優先順位を決められます。
また、対応は「すべて残す」か「何もしない」かの二択ではありません。重要度の高い案件はレベル3まで、影響の小さい案件はレベル1まで、というように目標を分ける進め方もあります。外注先の切り替えや内製化を急ぐ前に、現状を把握することから始めるのが現実的です。
よくある質問
外注先がコードの開示を嫌がる場合は?
まず、開示が難しい理由を確認します。他案件と共通する基盤を含んでいる、知的財産の扱いが定まっていない、といった事情が考えられます。コードそのものの開示が難しくても、データ定義書、分析ロジックの説明、再実行できる形での提供など、代替の方法で何が可能かを協議できる場合があります。可能であれば契約前に確認し、具体的な条項は法務部門などと検討してください。
エンジニアがいなくても残せますか?
データ定義書、分析ロジック記録、更新判断のルールは、文書として社内で管理できます。一方、再現手順書に沿った実行には専門知識が必要な場合があります。その場合は、実行そのものは外注先や第三者に依頼し、社内は「実行結果と記録を確認できる」状態から始める進め方もあります。ただし、誰でも同じようにできるようになるという意味ではありません。
既存案件も今から整理できますか?
整理できる可能性はありますが、資料が残っていない部分は、外注先の協力を得られるか、契約が継続しているかに左右されます。まず前節の3つの確認から始め、足りない資産を特定してください。
モデルの見直し頻度はどのくらいが目安ですか?
一律の頻度は示せません。業務の変化の速さ、予測の用途、誤差が事業に与える影響によって変わります。定期的に精度を確認する仕組みと、店舗の改装や商品構成の変更などが起きたときに随時見直す条件とを、分けて決めておくと運用しやすくなります。
まとめ:次に確認すること
データ分析の外注で問われるのは、外注するか内製するかではなく、外注したあとに社内が何をできる状態かです。本記事の要点は次の通りです。
- ブラックボックス化は、納品物の定義に過程が含まれていないことから起きやすい
- 社内に残すのは、自作の能力ではなく、説明・再実行・更新判断ができる状態
- そのために、データ定義・分析ロジック・再現手順を納品物として求め、更新判断のルールを決める
- 再現できることと、将来も同じ精度が出ることは別である
まずは既存案件を1件選び、3つの確認に答えられるかを見てみてください。
データ分析の外注は、社内に判断の根拠が残ってはじめて、経営に役立つ投資になると考えています。RASHINRA(経営判断の意思決定支援コンサルティング)では、データ定義・評価指標・更新判断の基準を、貴社の体制に合わせて整理する支援を行っています。外注先の選定前、契約更新前、既存モデルの見直し時など、検討の段階からご相談いただけます。