Changelog
Source:NEWS.md
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 の入口で書き直しています。
- 引数
row_numberの配線(reid_prefixed_columns())→ 4 つのscore_*() - 同点処理と NA ガード(
resolve_min_distance_ties())→match_greedy() - デコイ列(
raw_targetなど)による列取り違え → 4 つのscore_*() - タイブレークのシード固定・入力行順非依存・不偏性 →
match_greedy() - 返り値の契約(1 ANON 1 行、
success <= trial)→match_greedy()/reid_evaluate() - ノイズ耐性・単調性 →
match_greedy(score_*())
reid_result() が持っていた「ANON_ROW_NUMBER の重複を拒む」防御は、 より上流の validate_unique_candidate_pairs()(スコア表の入口)が 引き継いでいます(#60)。
内部の整理
-
R/reidentify.Rを削除し、新 API が依存していた内部ヘルパーを移しました。with_local_seed()→R/utils.R、resolve_min_distance_ties()→R/match.R、check_raw_anon_columns_exist()→R/score.R、validate_split()/parse_dist_values()/calc_KL()/distribution_distance()→R/distance.R、reid_stability()→R/evaluate.R。公開 API の振る舞いは変わりません。 - 旧 API 専用だった内部ヘルパー
as_reid_output()を削除しました。 - エクスポート関数は 55 個から 50 個になりました。
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 点しか取れませんでした)。リスクそのもの (割当結果・RESULT・success_analytic・success_mean・baseline・lift・top_k・RISK・max_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.2と0.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)。あわせて、統合結果が最良の単一軸を下回ったときにも 警告します。既定のridgeとcov_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)。