Skip to contents

reidentify 3.0.0 (2026-08-01)

従来 API(reid_by_*() / reid_result())を削除しました。 これが 3.0.0 のすべてです。ほかの機能・既定値・返り値は 2.0.0 から 変わっていません。

破壊的変更 — 関数を削除した

以下の 5 関数を削除しました(#84)。

削除した関数 置き換え
reid_by_num() match_greedy(score_num(pairs, "COL"))
reid_by_char() match_greedy(score_char(pairs, "COL"))
reid_by_dist() match_greedy(score_dist(pairs, "COL"))
reid_by_num_rank() match_greedy(score_num_rank(pairs, "COL"))
reid_result() reid_evaluate(scores)

2.0.0 の時点でこれらはすでに 3 層 API の薄いラッパで、内部では同じ score_*() + match_greedy() を呼んでいました。同じ引数・同じシードなら 上の置き換えは数値としても同一の結果を返します(2.0.0 の test-layers.R がシードごとに突き合わせていました)。

reid_result() だけは戻り値の形が変わります。" method: X , success / trial : 23 / 200" という文字列を返していましたが、この 2 つの数は reid_evaluate()per_seed$success / per_seed$trial から読めます。 reid_evaluate() はそれに加えてランダム割当のベースライン・シード違いの ばらつき・レコードごとのリスクを併記します。成功率を単独で出さないのは 意図的で、比較対象のない成功率は読めないためです (docs/lessons-learned.md §2)。

移行例

## 2.0.0
r <- reid_by_num(pairs, "AGE", seed = 1)
print(reid_result(r, method = "AGE"))

## 3.0.0
m <- match_greedy(score_num(pairs, "AGE"), seed = 1)   # 割当そのもの
reid_evaluate(score_num(pairs, "AGE"))                 # 評価つきの報告

reid_stability() は残っています。引数 reid_fn には (dat_raw_anon, target, ..., seed) を取る攻撃を渡します。従来 API を 渡していた箇所は、スコア層と割当層を 1 行で束ねてください。

## 2.0.0
reid_stability(reid_by_num, pairs, "AGE", seeds = 1:20)

## 3.0.0
attack_num <- function(dat, target, seed) {
  match_greedy(score_num(dat, target), seed = seed)
}
reid_stability(attack_num, pairs, "AGE", seeds = 1:20)

削除にあたって確認したこと

従来 API のテストの多くは、旧 API の入口を使って新 API と共有する内部を 検証していました。テストごと消せば検証が黙って弱くなり、CI は緑のまま 誰も気づきません(docs/lessons-learned.md §2 の失敗様式)。そこで、削除 した各テストが守っていた振る舞いを新 API の入口で書き直しています。

reid_result() が持っていた「ANON_ROW_NUMBER の重複を拒む」防御は、 より上流の validate_unique_candidate_pairs()(スコア表の入口)が 引き継いでいます(#60)。

内部の整理

reidentify 2.0.0 (2026-08-01)

1.0.0.0(2019 年)以来の最初の更新です。API を 3 層(スコア層 / 統合層 / 割当層)に分け、評価指標を増やし、いくつかの既定値を変えました。

同じコードに同じデータを与えても、以前と違う数値が出る箇所があります。 これは安全性評価ツールでは特に混乱の元なので、下の「破壊的変更」を先に 読んでください。既定変更の詳細な理由と実測値は docs/default-changes.md (https://github.com/gghatano/reidentify/blob/master/docs/default-changes.md) にあります。

バージョンを 1.0.0.0 から 2.0.0 に上げたのは、(a) 4 成分のバージョンが R の 慣行から外れていたことと、(b) 以下のとおり利用者の得る数値が変わる変更が 入っており semver では major に当たることの 2 点によります。

破壊的変更 — 既定値を変えた

  • match_greedy() / match_optimal() / reid_evaluate() / reid_per_anon()confidence の既定を "tie" から "margin" に変えました(#44)。 CONFIDENCE 列の値がすべて変わり、reid_evaluate()precision_recall の行数が増えます(連続スコアでは "tie" はほぼ全件が 1 に潰れ、閾値が 1 点しか取れませんでした)。リスクそのもの (割当結果・RESULTsuccess_analyticsuccess_meanbaselinelifttop_kRISKmax_riskは変わりません。 以前の数値は confidence = "tie" で再現できます。

  • 同点判定に相対許容誤差 tolerance を導入し、既定を sqrt(.Machine$double.eps)(約 1.5e-8)にしました(#61)。 reid_evaluate() / reid_confidence() / match_greedy() / match_optimal() が受け付けます。丸め誤差が同点判定に効いていたデータでは success_analytic / max_risk / RISK / TIE_SIZE / MARGIN / ECCENTRICITY / CONFIDENCE / precision_recall / top_k が変わります。 実測では、同じデータを整数単位で書くか 1/10 単位で書くかだけで max_risk が 0.5 と 1.0 に分かれていました(n=200 の構成で、真の per-record risk はどのレコードも厳密に 1/2)。整数スコアや、候補スコアが 8 桁以上離れているデータでは何も変わりません。 以前の数値は tolerance = 0 で再現できます。

  • unicity_fraction() / unicity() / 時空間ユニシティのキー生成を 作り直しました(#58, #70, #73)。列ごとに同値クラスの整数コードへ直して から連結し、double 列は tolerance を通します。以前は as.character() で 連結していたため、double が 15 桁で印字されて 0.1 + 0.20.3 が 同一視される一方、"\r" を含む文字列は別レコードを衝突させ、 属性を足すほど一意率が下がることがありました。時空間ユニシティでは 衝突がリスクを低く見せる向きに働いていました。一意率の数値が変わります。

破壊的変更 — 誤りを直したことで数値が変わる

いずれも「壊れていたものを直した」変更ですが、過去の報告書と数値が 合わなくなるため破壊的変更として挙げます。

  • reid_by_dist() にタイブレーク処理が無く、割り算の分母が候補行数に なっていました(#25)。同点が多いほど分母が膨らみ、報告される成功率が 小さく出ていました。
  • score_char() が一般化された列で停止せず、実リスクの約 1/4 という もっともらしい数値を返していました(#40)。
  • distribution_distance() の長さ合わせで、RAW と ANON の件数差が距離に 混入していました(#5)。分位点ベクトルの比較に変えました。
  • calc_KL() が KL ダイバージェンスの定義(非負性)を満たしていませんでした (#4)。総和正規化を入れました。
  • タイブレークが行順に依存していました(#3)。乱数化し、seed 引数と ばらつきの報告(reid_stability())を足しました。 reid_by_num_rank()rank(ties.method = "random") という第 2 の乱数源も seed に含めました。
  • row_number 引数が受け取られるだけで使われておらず、行番号列を改名した データではすべての reid_by_*() が失敗していました(#28)。
  • split 引数が正規表現として解釈され、"|""." を指定すると 壊れていました(#32)。リテラル文字列として扱います。
  • transform_transaction_to_master() の集計列名が、渡した引数の個数で 変わっていました(#26)。列数によらず同じ名前になります。
  • 重複した候補ペアがあると、解析値とシミュレーション値が揃って誤り、 自己整合チェックが機能していませんでした(#60)。 reid_evaluate() / match_greedy() が重複ペアを拒否します。

新しい警告 — 返り値は変わらない

いずれも「測定が静かに壊れている状態」を見つけるためのもので、 SCORE 列や返り値そのものは 1 ビットも変わりません。意図的な使い方であれば 黙らせられます。

  • score_multi() / score_by_knowledge() が、情報を持たない軸を検出して 警告します(既定 screen = "warn"、#35 / #43)。無情報な軸を等重みで 統合すると単一属性より成功率が下がるため、黙って過小報告になります。 screen = "none" で従来どおり。
  • combine_scores() が、重みをかけた後の成分の標準偏差の比が 10 倍を 超えると警告します(既定 scale_check = "warn"、#57)。 scale_check = "none" で従来どおり。
  • score_mahalanobis() が、共分散(ridge 適用後)の条件数が 100 を超えると 警告します(#59)。あわせて、統合結果が最良の単一軸を下回ったときにも 警告します。既定の ridgecov_from は変えていません。
  • lsh_candidates()attr(x, "blocking")"reid_blocking" クラスに なり、method / n_raw / n_anon / reduction / n_true_pairs / n_true_pairs_kept / recall が増えました(#36)。既存フィールドは すべて残ります。recall < 1 のとき警告します。
  • reid_evaluate()n_true_missing(正解が候補集合に無い件数)を 印字するようになりました(#56)。以前は計算しながら表示していなかったため、 「測定できていない」状態が「安全」と読めていました。

新機能

  • スコア層 / 統合層 / 割当層への API 分離(#11)。 score_*()combine_scores()match_greedy() / match_optimal()
  • 評価指標の拡充(#12)— ランダム / 最頻値のベースラインと lift、 精度–再現率曲線、Top-k、レコード別リスク、max_risk
  • 攻撃者知識モデル W / M / S(#13)— score_by_knowledge()
  • 多属性統合距離(#14)— 正規化・重み付き和・Mahalanobis。
  • グローバル最適割当(#15)— clue::solve_LSAP() によるハンガリアン法。
  • 信頼度付きマッチング(#16)— マージン / eccentricity と閾値による絞り込み。
  • IDF 重み付き一致スコア(#17)— 希少値の一致を重く数える。
  • 集合類似度によるマッチング(#18)— Jaccard / Tversky / min-hash / LSH。
  • 一般化・区間整合マッチングと一般化階層の外部定義(#20)。
  • ユニシティ測定(#21)— p 属性で一意になる割合。
  • 活動プロファイルによるスコア(#22)— 件数・曜日分布・活動期間。
  • Scoreboard-RH 型スコアリング(#23)— 疎データ向け。
  • 時空間ユニシティ(#24)— k 点で特定できる割合。
  • ブロッキングによる候補削減(#36)— 総当たり結合の n^2 を避けつつ、 取りこぼした正解ペアの割合(recall)を必ず報告する。

ドキュメントと開発基盤

  • vignette「なぜそう測るのか」を追加しました(#75)。
  • README をパッケージに追加し(#10)、実装との整合を CI で機械照合するように しました(#47 / #50 / #62)。README のコード例の #> 出力は毎回実行して 突き合わせています。
  • 公開ページ https://gghatano.github.io/reidentify/ を追加し(#48)、 そこに載る「テスト件数」「エクスポート関数の個数」を CI で照合するように しました(#63)。
  • testthat によるテスト基盤を導入しました(#7)。
  • roxygen コメントを関数本体の外に出し、ドキュメントを再生成できるように しました(#8)。
  • R CMD check --as-cran を CI で走らせ、NOTE でも落とすようにしました(#67)。
  • 2019 年にビルドされた同梱 PDF(55 関数中 46 個が載っていなかった)を 削除しました(#66)。
  • DESCRIPTION を現在の実装に合わせ、Authors@R / URL / BugReports / Depends: R (>= 4.1.0) を整備しました(#77)。

reidentify 1.0.0.0

  • 初版(GitHub のみ、CRAN 未公開)。reid_by_char() / reid_by_num() / reid_by_num_rank() / reid_by_dist() による 1 発呼び出しの API。