BigQueryの差分プライバシー機能を試してみた
こんにちは、京セラコミュニケーションシステム 立脇(@kccs_hiroshi-tatsuwaki)です。
突然ですが、皆さん「差分プライバシー」という概念をご存知でしょうか。世間では『データドリブン経営』の流れが活発になっていく一方、データの取り扱いについてはより機密性・厳密性を求められる時代となってきました。
製造業でも『製造業DX』という流れが活発化する一方で、生産情報や製法など機密データとして取り扱う必要があり、なかなか両立が難しい状況です。
そんな状況の中で利用できるソリューション、それが「差分プライバシー」機能です。
2023年7月時点、BigQueryの差分プライバシー機能がプレビュー公開となっています。なんでもBigQueryのUIからサクッと使えるとの触れ込みですので、一度試してみたいと思います。
なお、今回の記事ではBigQueryの差分プライバシー機能について取り扱います。
こちらのページに詳細の記載がありますので、個別の機能についてはこちらのページをご確認ください。
対象となる読者
BigQueryの一連の機能は知っているが、差分プライバシー機能についてよくわからない、というエンジニア
差分プライバシーの解説
ここからは、私が参考文献1を参考にしつつ、自身の学習も兼ねて差分プライバシーの概要を解説をしたいと思います。「ここが違うよ!」「これはこういう解釈のほうが正しい」等ありましたらコメントでご指摘お願いします。
差分プライバシーとは?
差分プライバシーとは要約すると以下となります。
- データの計算に関する標準のことで、出力によって公開される個人情報を制限します。
- データの共有や、個人グループに関する情報の推論を許可しながら、個人に関する情報が他者に知られることを防ぐために使用されます。
- 差分プライバシーは、プライバシーを保護する必要性と、統計分析の有用性に対するニーズのバランスを取るものです。プライバシーの保護が進むと、統計分析の有用性は低下し、逆もまた然りです。
差分プライバシー機能のユースケース
差分プライバシーのひとつのユースケースとして、個人に関する情報を含むデータセットから何らかの情報を取り出すための問合せを行う場合が挙げられます。問合せの結果である出力をそのまま利用すると、データセットに含まれる個人を識別し得る情報を暴露してしまう可能性があるため、データセットの分析結果にノイズを加えるなどして出力をランダム化し、データセットに含まれる情報が識別されにくくする方法があります。
たとえば男女20人のクラスにおける試験の結果を記録したデータセットから、「受験者の性別」と「合否結果」を抽出する問合せを実行する場合、差分プライバシーを用いることで、個人を特定されることなく、データセットから必要な情報を取り出すことができます。
差分プライバシー処理後のアウトプットの用途
差分プライバシー処理後のアウトプットは、個人情報を含むデータセットから必要な情報を取り出すために利用されます。
たとえば、医療データから病気の発生率を分析する場合、差分プライバシーを用いることで、個人を特定されることなく、病気の発生率を分析できます。また、マーケティング分析や社会調査などでも、差分プライバシー処理後のアウトプットを利用できます。
注意点としては下記があげられます。
- 差分プライバシー処理によってランダム化されたデータは、元のデータよりも精度が低下するため、その点に留意する必要があります。上記にも書きましたが、「プライバシー保護」と「統計分析の有用性」はトレードオフになります。
- 差分プライバシー処理されたデータが絶対的な匿名性を保証するものではありません。推測やデータの組み合わせにより、個人を特定することが可能となる場合があります。
絶対的な匿名性を保証できないシーンとは?
差分プライバシー処理を施しても「絶対的な匿名性を保証できないシーン」があります。
たとえば、データセットに含まれる個人が非常に少ない場合や、データセットに含まれる個人の属性が極端に偏っている場合、差分プライバシー処理後のデータから個人を特定することができる可能性があります。また、差分プライバシー処理後のデータを複数回利用する場合には、個人を特定することができる可能性があるため、注意が必要です。
絶対的な匿名性を実現するためには、セキュリティ対策やデータの小規模化、統計的な二次的特性の削除など、追加の措置が必要です。個人情報のプライバシーを保護するためには、データの取り扱いに関する法律や規制を遵守し、適切なセキュリティ対策を講じることが重要です。
ここまでのまとめ
差分プライバシー処理を施したからといって「完全に安全なデータになる」というわけではありません。「プライバシー保護」と「統計分析の有用性」のトレードオフを意識しつつ、用途や環境に合わせてこのトレードオフをチューニングしていくことが重要であることがわかると思います。
BigQueryの差分プライバシー機能を使ってみた
ここまでは文字ばかりのお勉強でした。ここからは実際に機能を使っていきたいと思います。
※ここからはJupyterNotebook上での操作を想定した記載になりますのでご注意ください。
事前準備
今回「差分プライバシー検証_実データ.csv」というファイルを用意しました。プライバシー処理を施す前の生データの位置づけです。2
home_dir = "../../differential-privacy_on_bigquery"
!rm -rf $home_dir
!mkdir -p $home_dir
PROJECT_ID="your_project"
csv_file_sample_data_of_production_line = '../../notebooks/differential-privacy/datas/差分プライバシー検証_実データ.csv'
csv_file_output_differential_privacy_on_bigquery=home_dir+"/output_differential_privacy_on_bigquery.csv"
import pandas as pd
df_src_data = pd.read_csv(csv_file_sample_data_of_production_line)
df_src_data
ratio1 | offset1 | offset2 | offset3 | offset4 | mode1 | mode2 | mode3 | value1 | value2 | ... | value5 | value6 | value7 | value8 | ratio2 | ratio3 | ratio4 | ratio5 | ratio6 | label | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 0.01 | 1 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | ... | 0 | 0 | 0 | 0 | 0.00189 | 0.0206 | 0.11118 | 0.099 | 0.11207 | 3 |
1 | 0.01 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | ... | 0 | 0 | 0 | 0 | 0.04300 | 0.0096 | 0.03375 | 0.103 | 0.03249 | 1 |
2 | 0.01 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | ... | 0 | 0 | 0 | 0 | 0.00160 | 0.0180 | 0.11900 | 0.104 | 0.11300 | 3 |
3 | 0.01 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | ... | 0 | 0 | 0 | 0 | 0.00879 | 0.0190 | 0.11300 | 0.086 | 0.13100 | 2 |
4 | 0.01 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | ... | 0 | 0 | 0 | 0 | 0.00150 | 0.0140 | 0.08200 | 0.074 | 0.11100 | 3 |
... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
3767 | 0.92 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | ... | 0 | 0 | 0 | 0 | 0.00070 | 0.0130 | 0.12000 | 0.084 | 0.14300 | 3 |
3768 | 0.93 | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | ... | 0 | 0 | 0 | 0 | 0.00270 | 0.0040 | 0.07700 | 0.086 | 0.09000 | 3 |
3769 | 0.93 | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | ... | 0 | 0 | 0 | 0 | 0.00300 | 0.0090 | 0.09200 | 0.081 | 0.11200 | 3 |
3770 | 0.94 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | ... | 0 | 0 | 0 | 0 | 0.00390 | 0.0206 | 0.15700 | 0.102 | 0.15400 | 3 |
3771 | 0.94 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | ... | 0 | 0 | 0 | 0 | 0.00190 | 0.0130 | 0.11900 | 0.104 | 0.11400 | 3 |
3772 rows × 22 columns
①CSVをBigQueryへロード
とにもかくにも生データ「差分プライバシー検証_実データ.csv」をBigQueryにロードします。
# テーブル名
bq_table_differential_privacy_on_bigquery01="differential_privacy.sample_data_of_production_line"
# スキーマファイルの定義
schema_file_differential_privacy_on_bigquery01 = home_dir + "/schema_file_differential_privacy_on_bigquery01.json"
print(schema_file_differential_privacy_on_bigquery01)
# スキーマファイルの生成
with open(schema_file_differential_privacy_on_bigquery01, 'w') as file:
file.write(
'[\
{"name":"RATIO1","type":"FLOAT","mode":"NULLABLE","description":"ratio1"},\
{"name":"OFFSET1","type":"FLOAT","mode":"NULLABLE","description":"offset1"},\
{"name":"OFFSET2","type":"FLOAT","mode":"NULLABLE","description":"offset2"},\
{"name":"OFFSET3","type":"FLOAT","mode":"NULLABLE","description":"offset3"},\
{"name":"OFFSET4","type":"FLOAT","mode":"NULLABLE","description":"offset4"},\
{"name":"MODE1","type":"FLOAT","mode":"NULLABLE","description":"mode1"},\
{"name":"MODE2","type":"FLOAT","mode":"NULLABLE","description":"mode2"},\
{"name":"MODE3","type":"FLOAT","mode":"NULLABLE","description":"mode3"},\
{"name":"VALUE1","type":"FLOAT","mode":"NULLABLE","description":"value1"},\
{"name":"VALUE2","type":"FLOAT","mode":"NULLABLE","description":"value2"},\
{"name":"VALUE3","type":"FLOAT","mode":"NULLABLE","description":"value3"},\
{"name":"VALUE4","type":"FLOAT","mode":"NULLABLE","description":"value4"},\
{"name":"VALUE5","type":"FLOAT","mode":"NULLABLE","description":"value5"},\
{"name":"VALUE6","type":"FLOAT","mode":"NULLABLE","description":"value6"},\
{"name":"VALUE7","type":"FLOAT","mode":"NULLABLE","description":"value7"},\
{"name":"VALUE8","type":"FLOAT","mode":"NULLABLE","description":"value8"},\
{"name":"RATIO2","type":"FLOAT","mode":"NULLABLE","description":"ratio2"},\
{"name":"RATIO3","type":"FLOAT","mode":"NULLABLE","description":"ratio3"},\
{"name":"RATIO4","type":"FLOAT","mode":"NULLABLE","description":"ratio4"},\
{"name":"RATIO5","type":"FLOAT","mode":"NULLABLE","description":"ratio5"},\
{"name":"RATIO6","type":"FLOAT","mode":"NULLABLE","description":"ratio6"},\
{"name":"LABEL","type":"INTEGER","mode":"NULLABLE","description":"label"}\
]'
)
# テーブルの削除
!bq rm --project_id $PROJECT_ID\
-f -t $bq_table_differential_privacy_on_bigquery01
# テーブル定義
!bq mk --project_id $PROJECT_ID\
--table \
$bq_table_differential_privacy_on_bigquery01 \
$schema_file_differential_privacy_on_bigquery01
../../differential-privacy_on_bigquery/schema_file_differential_privacy_on_bigquery01.json
Table 'your_project:differential_privacy.sample_data_of_production_line' successfully created.
# データをロード
!bq load \
--project_id $PROJECT_ID \
--allow_quoted_newlines \
--source_format=CSV \
--skip_leading_rows 1 \
--schema $schema_file_differential_privacy_on_bigquery01 \
$bq_table_differential_privacy_on_bigquery01 $csv_file_sample_data_of_production_line
Upload complete.
Waiting on bqjob_r18ad61682bd27886_0000018971e95c9e_1 ... (1s) Current status: DONE
念のためのCSVがロード確認する。
%%bigquery
SELECT * FROM `your_project.differential_privacy.sample_data_of_production_line`
RATIO1 | OFFSET1 | OFFSET2 | OFFSET3 | OFFSET4 | MODE1 | MODE2 | MODE3 | VALUE1 | VALUE2 | ... | VALUE5 | VALUE6 | VALUE7 | VALUE8 | RATIO2 | RATIO3 | RATIO4 | RATIO5 | RATIO6 | LABEL | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 0.64 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | ... | 0.0 | 1.0 | 0.0 | 0.0 | 0.00189 | 0.061 | 0.214 | 0.094 | 0.228 | 3 |
1 | 0.25 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 1.0 | ... | 0.0 | 0.0 | 0.0 | 0.0 | 0.03600 | 0.045 | 0.162 | 0.115 | 0.142 | 3 |
2 | 0.28 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | ... | 0.0 | 0.0 | 0.0 | 0.0 | 0.00090 | 0.045 | 0.204 | 0.203 | 0.100 | 3 |
3 | 0.59 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | ... | 0.0 | 0.0 | 0.0 | 0.0 | 0.00060 | 0.045 | 0.161 | 0.165 | 0.097 | 3 |
4 | 0.71 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | ... | 0.0 | 1.0 | 0.0 | 0.0 | 0.00020 | 0.045 | 0.125 | 0.082 | 0.152 | 3 |
... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
3767 | 0.87 | 1.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | ... | 0.0 | 0.0 | 0.0 | 0.0 | 0.00002 | 0.016 | 0.134 | 0.079 | 0.170 | 3 |
3768 | 0.90 | 1.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | ... | 0.0 | 0.0 | 0.0 | 0.0 | 0.00570 | 0.016 | 0.089 | 0.091 | 0.098 | 3 |
3769 | 0.04 | 1.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | ... | 0.0 | 0.0 | 0.0 | 0.0 | 0.00007 | 0.032 | 0.246 | 0.104 | 0.232 | 3 |
3770 | 0.16 | 1.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | ... | 1.0 | 0.0 | 0.0 | 0.0 | 0.00050 | 0.032 | 0.137 | 0.116 | 0.119 | 3 |
3771 | 0.46 | 1.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | ... | 0.0 | 0.0 | 0.0 | 0.0 | 0.00208 | 0.032 | 0.160 | 0.153 | 0.105 | 3 |
3772 rows × 22 columns
②プライバシー処理(SQL発行)
いよいよお待ちかねのプライバシー処理です。
https://cloud.google.com/bigquery/docs/reference/standard-sql/query-syntax#dp_clause
の「Differential privacy clause」に記載のあるDIFFERENTIAL_PRIVACYを利用します。
%%bigquery df_differential_privacy_data
SELECT
WITH
DIFFERENTIAL_PRIVACY OPTIONS(epsilon=1e20,
delta=.01,
privacy_unit_column=LABEL) LABEL,
AVG(RATIO1) as AVG_RATIO1,
AVG(OFFSET1) as AVG_OFFSET1,
AVG(OFFSET2) as AVG_OFFSET2,
AVG(OFFSET3) as AVG_OFFSET3,
AVG(OFFSET4) as AVG_OFFSET4,
AVG(MODE1) as AVG_MODE1,
AVG(MODE2) as AVG_MODE2,
AVG(MODE3) as AVG_MODE3,
AVG(VALUE1) as AVG_VALUE1,
AVG(VALUE2) as AVG_VALUE2,
AVG(VALUE3) as AVG_VALUE3,
AVG(VALUE4) as AVG_VALUE4,
AVG(VALUE5) as AVG_VALUE5,
AVG(VALUE6) as AVG_VALUE6,
AVG(VALUE7) as AVG_VALUE7,
AVG(VALUE8) as AVG_VALUE8,
AVG(RATIO2) as AVG_RATIO2,
AVG(RATIO3) as AVG_RATIO3,
AVG(RATIO4) as AVG_RATIO4,
AVG(RATIO5) as AVG_RATIO5,
AVG(RATIO6) as AVG_RATIO6,
FROM
`your_project.differential_privacy.sample_data_of_production_line`
GROUP BY
LABEL
ORDER BY 1
DIFFERENTIAL_PRIVACYに関する変数の説明は以下の通り。
- epsilon:結果に追加されるノイズの量を制御。イプシロンが高いほどノイズが少なくなる。
- delta:プライバシーが漏洩したと判断される確率。epsilonが一定の場合、deltaが小さいほど、プライバシーが強化される。
- max_groups_contributed:クエリの結果に含まれるグループの最大数。少ないほどプライバシーが強化される。
- privacy_unit_column:クエリの実行に使用されるデータセットの列を指定。この列は、プライバシーレベルを制御するために使用されるプライバシーユニット(保護したいプライバシーデータが一意となるキー列)を指定。ラベル的なもの。
このあと、中身の確認。
df_differential_privacy_data
LABEL | AVG_RATIO1 | AVG_OFFSET1 | AVG_OFFSET2 | AVG_OFFSET3 | AVG_OFFSET4 | AVG_MODE1 | AVG_MODE2 | AVG_MODE3 | AVG_VALUE1 | ... | AVG_VALUE4 | AVG_VALUE5 | AVG_VALUE6 | AVG_VALUE7 | AVG_VALUE8 | AVG_RATIO2 | AVG_RATIO3 | AVG_RATIO4 | AVG_RATIO5 | AVG_RATIO6 | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 1 | 0.498710 | 0.236559 | 0.096774 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.021505 | 0.021505 | ... | 0.000000 | 0.000000 | 0.021505 | 0.000000 | 0.000000 | 0.093412 | 0.009658 | 0.033767 | 0.103753 | 0.033039 |
1 | 2 | 0.524293 | 0.219895 | 0.000000 | 0.015707 | 0.005236 | 0.057592 | 0.000000 | 0.000000 | 0.015707 | ... | 0.005236 | 0.000000 | 0.031414 | 0.000000 | 0.041885 | 0.013952 | 0.017463 | 0.091598 | 0.099963 | 0.092124 |
2 | 3 | 0.515036 | 0.309346 | 0.130734 | 0.013188 | 0.012041 | 0.038417 | 0.015195 | 0.014908 | 0.014908 | ... | 0.005161 | 0.009461 | 0.024943 | 0.000287 | 0.051032 | 0.001894 | 0.020622 | 0.111187 | 0.099132 | 0.113197 |
3 rows × 22 columns
上記はグルーピングの際にプライバシー処理を施している形になります。
さいごに
本当は、ここから実際に特徴量がどれくらい保存されているか、などをdeltaやepsilonを編集し用途にあわえてチューニングしていくフェーズに入るのですが、長くなってしまうのでここでは割愛します。
BigQueryの差分プライバシー機能とは、複雑な知識の理解はそこそこにして、前準備さえ整っていればBigQueryのSQLであっさりと実現できてしまう機能であることがわかると思います。
Webの世界ではHTTPで生データをやり取りをすることが通常でしたが、いまやHTTPSで秘匿化が当たり前の世界になっています。
AIで活用する構造化データの送受信でも、このような技術で秘匿化することが当たり前になりそうですね。