データエンジニア向けSnowflakeプライバシー保護機能②合成データ
はじめに
データ駆動型の意思決定がビジネスの重要な要素となる中、プライバシー保護とデータ活用の両立は多くの組織にとって重要な課題となっています。前回の記事では、Snowflakeのプライバシー保護の各機能について解説しました。
2024年10月28日、Snowflakeは新たなプライバシー保護機能として合成データ生成機能をプレビューリリースしました。この機能の追加により、Snowflakeのプライバシー保護機能は、アクセス制御やデータマスキングといった従来の保護手法に加え、より積極的なデータ活用を可能にする選択肢を提供しています。
プレビュー機能として提供される本機能は、開発環境でのテストデータ生成や、プライバシーを考慮したデータ分析など、様々なユースケースでの活用が期待されます。本記事では、この新機能の検証を通じて、その特徴と活用方法について考察して内容を自分なりにまとめてみました。
1. 合成データの概要
1.1 技術的概要
合成データとは、実データの統計的特性を保持しながら、人工的に生成された新しいデータセットです。
Snowflakeの合成データ生成機能
snowlfakeでは、GENERATE_SYNTHETIC_DATA
というストアドプロシージャにより、合成データを作成できます
このストアドプロシージャは、コピュラをベースとした機械学習技術を用いて、元データの分布や関係性を学習して新たなデータを生成します
コピュラにより、以下を実現することが期待できます
- 個々のレコードは完全に人工的に生成
- 統計的な特性は元データを維持
- データ間の関連性も考慮した生成が可能
このコピュラなどの合成データに関する技術は、先日投稿した以下の記事を参考にしてください
合成データのアルゴリズムはいずれディープラーニングや生成AIレベルになることで、さらに有用度上がるのではないかと期待しています
1.2 ビジネス上の意義
さて、生成されら合成データの活用により、以下のようなビジネス価値の提供が期待されます
-
開発・テスト環境での活用
- 本番データを使用せずに現実的なテストが可能
- セキュリティリスクの軽減
- 開発サイクルの効率化
-
データ分析での活用
- プライバシーを考慮した分析環境の提供
- データサイエンティストの早期参画
- 探索的なデータ分析の促進
-
コンプライアンス対応
- 規制要件への対応
- データ共有における新たな選択肢
- プライバシーリスクの低減
1は分かりやすいですね。精度よりも一定レベルのデータセットが欲しいケースは多々あります
2や3はどうでしょう。プライバシーの保護と分析データとしての精度は悩ましい課題です
1.3 プライバシー保護機能との比較
上記を踏まえた従来のプライバシー保護機能と合成データの特徴を比較してみました
機能 | 保護レベル | 実装の複雑さ | 性能影響 | 主な使用シナリオ | リスクや懸念事項 |
---|---|---|---|---|---|
動的データマスキング | 中 | 中 | 低 | 特定のユーザーや状況に応じたデータ保護 | 不適切な条件設定でデータ露出のリスク |
行アクセスポリシー | 高 | 中 | 中 | ロール別・ユーザー別のアクセス制御 | ポリシーの複雑化による管理オーバーヘッド |
ハッシュ化・暗号化 | 高 | 低 | 低 | 機密データの保存・転送時の保護 | 鍵管理の複雑さ、暗号化処理の遅延 |
セキュアビュー | 中 | 低 | 中 | 必要最低限のデータアクセスの提供 | 設計ミスによる露出リスク、パフォーマンス低下 |
集計ポリシー | 中 | 中 | 中 | 小規模グループに対する統計的保護 | 厳格すぎるポリシーによる分析の制約 |
投影ポリシー | 中 | 中 | 低 | プライバシー項目の出力制御 | 設計ミスによる露出リスク |
差分プライバシー | 高 | 高 | 高 | 高度な匿名化と統計的有用性の両立 | ノイズ追加でデータ精度が低下する可能性 |
合成データ | 高 | 高 | 低 | 元データとの完全な分離 開発/テスト環境での利用 規制対応したデータ共有 |
モデルの品質管理の複雑さ 生成データの品質保証 統計的特性の検証必要性 |
合成データは、既存のプライバシー保護機能を補完する新たなアプローチとして位置づけられます
-
アクセス制御との関係:
より積極的なデータ活用を可能にする選択肢を提供 -
マスキング機能との関係:
データの有用性を維持しながら、より強力な保護を実現 -
差分プライバシーとの関係:
異なるアプローチでプライバシー保護を実現する補完的な技術
2. 合成データ生成の実装
では、生成工程に入るに辺り、snowflakeの公式ドキュメントを読み解いた上で、その前提事項をまとめてみます。
項目 | 制限値/要件 | 備考 |
---|---|---|
エディション | Enterprise以上 | - |
行数 | 最低でも20個の異なる行 | データバリエーションが必要 |
サポート対象テーブル | 標準テーブル、ビュー | 外部テーブル非対応 |
入力テーブル | 最大5個まで | 入力テーブルごとに最大100列 |
タイムスタンプ | TIMESTAMP_NTZ | 他のタイムスタンプ型は非対応 |
レコード上限 | 2,800,000 | サポートに問い合わせして確認 |
複数のテーブルを同時にプロシージャに掛けることで結合キーなどを揃える事が出来るのは良い!
2.1 とりあえず叩いてみる
新機能を前回のハンズオンデータでとりあえず実行してみます!
USE ROLE PRIVACY_HO_ADMIN;
CALL SNOWFLAKE.DATA_PRIVACY.GENERATE_SYNTHETIC_DATA({
'datasets': [{
'input_table': 'PRIVACY_HO_DB.PRIVACY.CUSTOMER_DATA',
'output_table': 'PRIVACY_HO_DB.PRIVACY.SYNTHETIC_CUSTOMER_DATA',
'columns': {
'CUSTOMER_ID': {'join_key': true} -- 顧客IDを結合キーとして指定
}
}],
'privacy_filter': true, -- プライバシーフィルターを有効化
'replace_output_tables': true -- 既存の出力テーブルを上書き
});
210012 (P0000): Synthetic data generation feature is not enabled for this account
-- ちょ、使えないじゃん・・
-- サポートに問い合わせして有効にしてもらう必要があるようです・・
-- ・・・サポートから有効になったよという連絡を頂いたので再実行
USE ROLE PRIVACY_HO_ADMIN;
CALL SNOWFLAKE.DATA_PRIVACY.GENERATE_SYNTHETIC_DATA({
'datasets': [{
'input_table': 'PRIVACY_HO_DB.PRIVACY.CUSTOMER_DATA',
'output_table': 'PRIVACY_HO_DB.PRIVACY.SYNTHETIC_CUSTOMER_DATA',
'columns': {
'CUSTOMER_ID': {'join_key': true} -- 顧客IDを結合キーとして指定
}
}],
'privacy_filter': true, -- プライバシーフィルターを有効化
'replace_output_tables': true -- 既存の出力テーブルを上書き
});
-- クエリで結果が生成されませんでした
-- どうも5件程度だと生成してくれないみたいです・・
-- 作成上限についてはサポートに問い合わせした情報を上のまとめに載せています
さて、前回の記事ではテストデータを作成しましたが、今回は人工データから合成データを作るというのも違和感があり、本番相当のデータセットを用意するため、久しぶりにsnowflakeが提供してくれている、TPCのサンプルデータセットSNOWFLAKE_SAMPLE_DATA
を使おうと思います
(まぁ、これも本質的には人工データなのですが・・)
2.2 前準備
TPCより検証用のデータを切り出して作成します
実行クエリ(長いので折りたたみ)
-- 1. 環境設定
USE ROLE PRIVACY_HO_ADMIN;
USE DATABASE PRIVACY_HO_DB;
USE SCHEMA PRIVACY;
-- 2. アクティブな顧客の抽出
CREATE OR REPLACE TABLE PRIVACY_HO_DB.PRIVACY.TPC_ACTIVE_CUSTOMERS AS
WITH customer_sales AS (
SELECT
ss_customer_sk,
COUNT(*) as transaction_count,
COUNT(DISTINCT d.d_date) as unique_dates,
SUM(ss_net_paid) as total_spent
FROM SNOWFLAKE_SAMPLE_DATA.TPCDS_SF10TCL.store_sales ss
JOIN SNOWFLAKE_SAMPLE_DATA.TPCDS_SF10TCL.date_dim d
ON ss.ss_sold_date_sk = d.d_date_sk
WHERE d.d_date BETWEEN TO_DATE('2000-01-01') AND TO_DATE('2000-01-31') -- 1ヶ月
GROUP BY ss_customer_sk
),
target_customers AS (
SELECT ss_customer_sk
FROM customer_sales
WHERE transaction_count >= 5
AND unique_dates >= 3
ORDER BY total_spent DESC
LIMIT 5000 -- 顧客数を5,000に調整
)
SELECT
c.c_customer_sk,
c.c_customer_id,
c.c_first_name,
c.c_last_name,
TO_DATE(c.c_birth_year || '-' ||
LPAD(c.c_birth_month::VARCHAR, 2, '0') || '-' ||
LPAD(c.c_birth_day::VARCHAR, 2, '0')) as birth_date,
c.c_email_address,
c.c_preferred_cust_flag = 'Y' as is_preferred_customer,
COALESCE(c.c_birth_country, 'UNKNOWN') as birth_country,
d2.d_date as first_purchase_date,
c.c_current_addr_sk,
c.c_current_cdemo_sk,
c.c_current_hdemo_sk
FROM SNOWFLAKE_SAMPLE_DATA.TPCDS_SF10TCL.customer c
INNER JOIN target_customers t
ON c.c_customer_sk = t.ss_customer_sk
LEFT JOIN SNOWFLAKE_SAMPLE_DATA.TPCDS_SF10TCL.date_dim d2
ON c.c_first_sales_date_sk = d2.d_date_sk;
-- 3. 売上データの抽出
CREATE OR REPLACE TABLE PRIVACY_HO_DB.PRIVACY.TPC_STORE_SALES AS
WITH limited_sales AS (
SELECT
s.ss_customer_sk,
s.ss_store_sk,
d.d_date as sale_date,
s.ss_ticket_number,
s.ss_quantity,
ROUND(s.ss_wholesale_cost, 2) as wholesale_cost,
ROUND(s.ss_list_price, 2) as list_price,
ROUND(s.ss_sales_price, 2) as sales_price,
ROUND(s.ss_ext_discount_amt, 2) as discount_amount,
ROUND(s.ss_ext_sales_price, 2) as extended_sales_price,
ROUND(s.ss_ext_wholesale_cost, 2) as extended_wholesale_cost,
ROUND(s.ss_ext_list_price, 2) as extended_list_price,
ROUND(s.ss_ext_tax, 2) as tax_amount,
ROUND(s.ss_coupon_amt, 2) as coupon_amount,
ROUND(s.ss_net_paid, 2) as net_paid_amount,
ROUND(s.ss_net_paid_inc_tax, 2) as net_paid_inc_tax,
ROUND(s.ss_net_profit, 2) as net_profit,
ROW_NUMBER() OVER (PARTITION BY s.ss_customer_sk ORDER BY d.d_date, s.ss_ticket_number) as rn
FROM SNOWFLAKE_SAMPLE_DATA.TPCDS_SF10TCL.store_sales s
JOIN SNOWFLAKE_SAMPLE_DATA.TPCDS_SF10TCL.date_dim d
ON s.ss_sold_date_sk = d.d_date_sk
INNER JOIN PRIVACY_HO_DB.PRIVACY.TPC_ACTIVE_CUSTOMERS c
ON s.ss_customer_sk = c.c_customer_sk
WHERE d.d_date BETWEEN TO_DATE('2000-01-01') AND TO_DATE('2000-01-31')
)
SELECT
ss_customer_sk,
ss_store_sk,
sale_date,
ss_ticket_number,
ss_quantity,
wholesale_cost,
list_price,
sales_price,
discount_amount,
extended_sales_price,
extended_wholesale_cost,
extended_list_price,
tax_amount,
coupon_amount,
net_paid_amount,
net_paid_inc_tax,
net_profit
FROM limited_sales;
-- 4. 店舗データの抽出
CREATE OR REPLACE TABLE PRIVACY_HO_DB.PRIVACY.TPC_STORE AS
SELECT DISTINCT
s.s_store_sk,
s.s_store_id,
s.s_rec_start_date,
s.s_rec_end_date,
s.s_store_name,
s.s_number_employees,
s.s_floor_space,
s.s_hours,
s.s_manager,
s.s_market_id,
INITCAP(s.s_geography_class) as geography_class,
s.s_market_desc,
s.s_market_manager,
s.s_division_id,
s.s_division_name,
s.s_company_id,
s.s_company_name,
TRIM(s.s_street_number) as street_number,
TRIM(s.s_street_name) as street_name,
TRIM(s.s_street_type) as street_type,
TRIM(s.s_suite_number) as suite_number,
INITCAP(s.s_city) as city,
INITCAP(s.s_county) as county,
UPPER(s.s_state) as state,
REGEXP_REPLACE(s.s_zip, '[^0-9]', '') as zip_code,
INITCAP(s.s_country) as country,
s.s_gmt_offset,
s.s_tax_precentage as tax_percentage
FROM SNOWFLAKE_SAMPLE_DATA.TPCDS_SF10TCL.store s
INNER JOIN PRIVACY_HO_DB.PRIVACY.TPC_STORE_SALES ss
ON s.s_store_sk = ss.ss_store_sk;
-- 5. データ量の確認
SELECT
'Extracted Data Overview' as description,
(SELECT COUNT(DISTINCT ss_customer_sk) FROM PRIVACY_HO_DB.PRIVACY.TPC_STORE_SALES) as unique_customers,
(SELECT COUNT(*) FROM PRIVACY_HO_DB.PRIVACY.TPC_STORE_SALES) as total_transactions,
(SELECT COUNT(DISTINCT ss_store_sk) FROM PRIVACY_HO_DB.PRIVACY.TPC_STORE_SALES) as unique_stores,
(SELECT MIN(sale_date) FROM PRIVACY_HO_DB.PRIVACY.TPC_STORE_SALES) as min_date,
(SELECT MAX(sale_date) FROM PRIVACY_HO_DB.PRIVACY.TPC_STORE_SALES) as max_date;
DESCRIPTION | UNIQUE_CUSTOMERS | TOTAL_TRANSACTIONS | UNIQUE_STORES | MIN_DATE | MAX_DATE |
---|---|---|---|---|---|
Extracted Data Overview | 4999 | 1757083 | 750 | 2000-01-01 | 2000-01-31 |
ユーザー5000人弱、200万件弱のデータを準備しました
2.3 合成データの作成
データ準備が出来たのでストアドプロシージャGENERATE_SYNTHETIC_DATA
を実行します
-- 6. 合成データの生成
CALL SNOWFLAKE.DATA_PRIVACY.GENERATE_SYNTHETIC_DATA({
'datasets': [{
'input_table': 'PRIVACY_HO_DB.PRIVACY.TPC_STORE_SALES',
'output_table': 'PRIVACY_HO_DB.PRIVACY.SYNTHETIC_TPC_STORE_SALES',
'columns': {
'ss_customer_sk': {'join_key': true}, --結合キーの指定
'ss_store_sk': {'join_key': true} --結合キーの指定
}
},
{
'input_table': 'PRIVACY_HO_DB.PRIVACY.TPC_ACTIVE_CUSTOMERS',
'output_table': 'PRIVACY_HO_DB.PRIVACY.SYNTHETIC_TPC_CUSTOMERS',
'columns': {
'c_customer_sk': {'join_key': true}
}
},
{
'input_table': 'PRIVACY_HO_DB.PRIVACY.TPC_STORE',
'output_table': 'PRIVACY_HO_DB.PRIVACY.SYNTHETIC_TPC_STORE',
'columns': {
's_store_sk': {'join_key': true}
}
}],
'privacy_filter': true, --プライバシー項目を除外する設定
'replace_output_tables': true --同名テーブルを置き換える設定
});
-- データ量にもよりますが、数分程度で完了しました
-- TPC_ACTIVE_CUSTOMERSを5件ずつ比較
select * from
(select 'Synthetic',S.* from PRIVACY_HO_DB.PRIVACY.SYNTHETIC_TPC_CUSTOMERS S
limit 5 )
union
select * from
(
select 'Original',O.* from PRIVACY_HO_DB.PRIVACY.TPC_ACTIVE_CUSTOMERS O
limit 5 )
order by 1
-- TPC_STORE_SALESを5件ずつ比較
select * from
(select 'Synthetic',S.* from PRIVACY_HO_DB.PRIVACY.SYNTHETIC_TPC_STORE_SALES S
limit 5 )
union
select * from
(
select 'Original',O.* from PRIVACY_HO_DB.PRIVACY.TPC_STORE_SALES O
limit 5 )
order by 1
-- TPC_STOREを5件ずつ比較
select * from
(select 'Synthetic',S.* from PRIVACY_HO_DB.PRIVACY.TPC_STORE S
limit 5 )
union
select * from
(
select 'Original',O.* from PRIVACY_HO_DB.PRIVACY.TPC_STORE O
limit 5 )
order by 1
1. 顧客データ(TPC_ACTIVE_CUSTOMERS)の特徴
'SYNTHETIC' | C_CUSTOMER_SK | C_CUSTOMER_ID | C_FIRST_NAME | C_LAST_NAME | BIRTH_DATE | C_EMAIL_ADDRESS | IS_PREFERRED_CUSTOMER | BIRTH_COUNTRY | FIRST_PURCHASE_DATE | C_CURRENT_ADDR_SK | C_CURRENT_CDEMO_SK | C_CURRENT_HDEMO_SK |
---|---|---|---|---|---|---|---|---|---|---|---|---|
Original | 2426391 | AAAAAAAAHBGAFCAA | Stark | FALSE | UNKNOWN | 24341120 | 1718305 | |||||
Original | 23688982 | AAAAAAAAGBHHJGBA | Daniel | Roddy | Daniel.Roddy@hEp9cF5PV.com | AUSTRALIA | 3866630 | 956145 | ||||
Original | 6490373 | AAAAAAAAFAJADGAA | UNKNOWN | 19754956 | 63008 | |||||||
Original | 63067508 | AAAAAAAAEHFFCMDA | UNKNOWN | 20245278 | 569540 | 2609 | ||||||
Original | 37066874 | AAAAAAAAKHIJFDCA | Emanuel | Emanuel.Smith@v3.org | UNKNOWN | 24566915 | ||||||
Synthetic | 4705 | redacted | Robert | King | 1946-09-06 | redacted | FALSE | NETHERLANDS ANTILLES | 1995-03-13 | 11770157 | 1710956 | 3369 |
Synthetic | 4080 | redacted | Min | Freeman | 1982-10-29 | redacted | FALSE | PERU | 2000-07-24 | 14506015 | 1912302 | 1893 |
Synthetic | 4666 | redacted | Kristy | Ward | 1948-02-02 | redacted | FALSE | SOUTH AFRICA | 1994-03-23 | 32473528 | 33261 | 4704 |
Synthetic | 4509 | redacted | Larry | Lacey | 1949-12-20 | redacted | FALSE | CHRISTMAS ISLAND | 1998-01-09 | 21121523 | 1375904 | 3324 |
Synthetic | 5317 | redacted | Danny | Murray | 1979-08-28 | redacted | FALSE | ARMENIA | 1998-11-14 | 1527925 | 1396072 | 6591 |
プライバシー保護の観点
-
適切なマスキング
- C_CUSTOMER_ID: 自動的にredacted処理
- メールアドレス: 個人情報として適切にマスキング
データの質
-
個人属性の生成
- 名前: 実在しそうな組み合わせを生成
- 生年月日: 妥当な日付範囲で生成
- 出身国: 実在する国名で生成
要注意点
- 名前(FIRST_NAME, LAST_NAME)が個人情報判定から漏れている可能性
- プライバシー項目は明示的な指定が推奨
2. 売上データ(TPC_STORE_SALES)の特徴
'SYNTHETIC' | SS_CUSTOMER_SK | SS_STORE_SK | SALE_DATE | SS_TICKET_NUMBER | SS_QUANTITY | WHOLESALE_COST | LIST_PRICE | SALES_PRICE | DISCOUNT_AMOUNT | EXTENDED_SALES_PRICE | EXTENDED_WHOLESALE_COST | EXTENDED_LIST_PRICE | TAX_AMOUNT | COUPON_AMOUNT | NET_PAID_AMOUNT | NET_PAID_INC_TAX | NET_PROFIT |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Original | 30087047 | 1210 | 2000-01-01 | 2333112523 | 84 | 42.37 | 53.8 | 27.97 | 0 | 2349.48 | 3559.08 | 4519.2 | 70.48 | 0 | 2349.48 | 2419.96 | -1209.6 |
Original | 30087047 | 1210 | 2000-01-01 | 2333112523 | 84 | 17.96 | 30.53 | 28.08 | 0 | 2358.72 | 1508.64 | 2564.52 | 94.34 | 0 | 2358.72 | 2453.06 | 850.08 |
Original | 30087047 | 1210 | 2000-01-01 | 2333112523 | 46 | 25.32 | 36.71 | 16.51 | 0 | 759.46 | 1164.72 | 1688.66 | 0 | 0 | 759.46 | 759.46 | -405.26 |
Original | 30087047 | 1210 | 2000-01-01 | 2333112523 | 76 | 39.84 | 76.09 | 35.76 | 924.03 | 2717.76 | 3027.84 | 5782.84 | 143.49 | 924.03 | 1793.73 | 1937.22 | -1234.11 |
Original | 30087047 | 1210 | 2000-01-01 | 2333112523 | 52 | 29.87 | 45.4 | 2.27 | 0 | 118.04 | 1553.24 | 2360.8 | 3.54 | 0 | 118.04 | 121.58 | -1435.2 |
Synthetic | 2297 | 550 | 2000-01-17 | 2297831383 | 95 | 66.991162603 | 48.992248761 | 7.02481308 | 0 | 60.631075264 | 49.29781438 | 969.044091054 | 0 | 0 | 299.619216849 | 398.236908552 | -93.574282746 |
Synthetic | 2297 | 550 | 2000-01-06 | 2178927794 | 32 | 69.866549734 | 106.929340341 | 14.83638324 | 0 | 6185.358913366 | 4740.862160021 | 231.432882902 | 177.49029919 | 0 | 13278.914290739 | 2617.399862003 | -886.754448875 |
Synthetic | 2297 | 550 | 2000-01-07 | 2181496852 | 82 | 98.128154848 | 103.23621389 | 19.772316501 | 0 | 665.039938418 | 1646.930825931 | 1219.627551787 | 275.005458339 | 0 | 3569.594069511 | 122.413919391 | -222.127038136 |
Synthetic | 2297 | 550 | 2000-01-06 | 2332694656 | 88 | 60.616915394 | 1.412923673 | 3.883619321 | 0 | 167.33684514 | 751.730717233 | 6168.150009188 | 20.128009595 | 0 | 268.205989911 | 4577.438889041 | -31.051056746 |
Synthetic | 3706 | 731 | 2000-01-16 | 1296090028 | 35 | 81.218504739 | 10.350438991 | 43.204118001 | 0 | 643.484351842 | 237.470683524 | 3882.768723163 | 77.87849924 | 0 | 71.545533844 | 629.147126697 | 80.764355158 |
数値データの生成
-
金額関連
- 妥当な範囲内での数値生成
- 計算項目間の整合性は維持
取引の特徴
-
日付
- 指定期間内(2000年1月)での適切な分散
-
取引ID
- ユニークな値を適切に生成
特筆事項
- 複雑な計算関係(税額、純利益など)も論理的な範囲内で生成
- 極端な外れ値は見られない
3. 店舗データ(TPC_STORE)の特徴
'SYNTHETIC' | S_STORE_SK | S_STORE_ID | S_REC_START_DATE | S_REC_END_DATE | S_STORE_NAME | S_NUMBER_EMPLOYEES | S_FLOOR_SPACE | S_HOURS | S_MANAGER | S_MARKET_ID | GEOGRAPHY_CLASS | S_MARKET_DESC | S_MARKET_MANAGER | S_DIVISION_ID | S_DIVISION_NAME | S_COMPANY_ID | S_COMPANY_NAME | STREET_NUMBER | STREET_NAME | STREET_TYPE | SUITE_NUMBER | CITY | COUNTY | STATE | ZIP_CODE | COUNTRY | S_GMT_OFFSET | TAX_PERCENTAGE |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Original | 373 | AAAAAAAAFHBAAAAA | 1997-03-13 | pri | 298 | 6901716 | 8AM-4PM | Alvin Anderson | 1 | Unknown | Regardless generous problems could not win that rare | Ervin Garcia | 1 | Unknown | 1 | Unknown | 639 | College Railroad | Cir. | Suite 340 | Riverdale | Sumner County | TN | 39391 | United States | -6.00 | 0.00 | |
Original | 1004 | AAAAAAAAMODAAAAA | 1997-03-13 | 2000-03-12 | ese | 253 | 7499231 | 8AM-4PM | Gordon Schuler | 9 | Unknown | Everyday, young proc | Henry Erickson | 1 | Unknown | 1 | Unknown | 337 | Willow Third | Court | Suite S | Oak Grove | Ziebach County | SD | 58370 | United States | -6.00 | 0.07 |
Original | 523 | AAAAAAAALACAAAAA | 1997-03-13 | pri | 266 | 9144192 | 8AM-4PM | Kristopher Jackson | 2 | Unknown | Very emotional guidelines try from an schools; real teachers | Elton Morgan | 1 | Unknown | 1 | Unknown | 429 | 2nd Pine | Way | Suite W | Belmont | Grant County | KS | 60191 | United States | -6.00 | 0.08 | |
Original | 1498 | AAAAAAAAKNFAAAAA | 1997-03-13 | 1999-03-13 | eing | 284 | 6791830 | 8AM-4PM | Seth Williams | 6 | Unknown | Existing, reasonable historians shall start. Mine | Timothy Renteria | 1 | Unknown | 1 | Unknown | 562 | River | Circle | Suite 400 | Brownsville | Mariposa County | CA | 99310 | United States | -8.00 | 0.06 |
Original | 1480 | AAAAAAAAIMFAAAAA | 1997-03-13 | 1999-03-13 | bar | 297 | 6209516 | 8AM-4PM | Charles Jordan | 1 | Unknown | Full principles know successful companies. Apparently sudden reforms wil | Scott Porter | 1 | Unknown | 1 | Unknown | 845 | Park Woodland | Court | Suite Q | Oakland | Stillwater County | MT | 69843 | United States | -7.00 | 0.08 |
Synthetic | 373 | AAAAAAAAFHBAAAAA | 1997-03-13 | pri | 298 | 6901716 | 8AM-4PM | Alvin Anderson | 1 | Unknown | Regardless generous problems could not win that rare | Ervin Garcia | 1 | Unknown | 1 | Unknown | 639 | College Railroad | Cir. | Suite 340 | Riverdale | Sumner County | TN | 39391 | United States | -6.00 | 0.00 | |
Synthetic | 1004 | AAAAAAAAMODAAAAA | 1997-03-13 | 2000-03-12 | ese | 253 | 7499231 | 8AM-4PM | Gordon Schuler | 9 | Unknown | Everyday, young proc | Henry Erickson | 1 | Unknown | 1 | Unknown | 337 | Willow Third | Court | Suite S | Oak Grove | Ziebach County | SD | 58370 | United States | -6.00 | 0.07 |
Synthetic | 523 | AAAAAAAALACAAAAA | 1997-03-13 | pri | 266 | 9144192 | 8AM-4PM | Kristopher Jackson | 2 | Unknown | Very emotional guidelines try from an schools; real teachers | Elton Morgan | 1 | Unknown | 1 | Unknown | 429 | 2nd Pine | Way | Suite W | Belmont | Grant County | KS | 60191 | United States | -6.00 | 0.08 | |
Synthetic | 1498 | AAAAAAAAKNFAAAAA | 1997-03-13 | 1999-03-13 | eing | 284 | 6791830 | 8AM-4PM | Seth Williams | 6 | Unknown | Existing, reasonable historians shall start. Mine | Timothy Renteria | 1 | Unknown | 1 | Unknown | 562 | River | Circle | Suite 400 | Brownsville | Mariposa County | CA | 99310 | United States | -8.00 | 0.06 |
Synthetic | 1480 | AAAAAAAAIMFAAAAA | 1997-03-13 | 1999-03-13 | bar | 297 | 6209516 | 8AM-4PM | Charles Jordan | 1 | Unknown | Full principles know successful companies. Apparently sudden reforms wil | Scott Porter | 1 | Unknown | 1 | Unknown | 845 | Park Woodland | Court | Suite Q | Oakland | Stillwater County | MT | 69843 | United States | -7.00 | 0.08 |
データの一貫性
- マスタ的な情報は高い一貫性を維持
- 住所や組織情報の整合性が保持
地理情報
- 州、郵便番号の整合性を維持
- タイムゾーン(GMT_OFFSET)との整合性も保持
コード体系
- ID体系の一貫性を維持
- 階層構造(会社-部門-店舗)の保持
要注意点
- 名前(S_MARKET_MANAGER)が個人情報判定から漏れている可能性
- プライバシー項目は明示的な指定が推奨
データの外観については確認できました。続いてデータの品質面に着目して評価をしてみましょう
2.4 相関係数の妥当性分析
さて、ストアドプロシージャの完了時の実行結果情報として各数値の相関係数が表示されます
METRIC_TYPE
は CORRELATION_COEFFICIENT_DIFFERENCE(相関係数差)に対し、
相関比較項目とその相関係数値が出力されるため、それらについて抜粋して考察しました
SOURCE_COLUMNS | METRIC_VALUE |
---|---|
DISCOUNT_AMOUNT,COUPON_AMOUNT | 0.998945704 |
NET_PAID_AMOUNT,NET_PAID_INC_TAX | 0.998638155 |
WHOLESALE_COST,LIST_PRICE | 0.930156857 |
SALES_PRICE,EXTENDED_SALES_PRICE | 0.764293259 |
TAX_AMOUNT,NET_PAID_AMOUNT | 0.776160713 |
SS_QUANTITY,NET_PROFIT | 0.27239076 |
LIST_PRICE,NET_PROFIT | 0.1721833 |
S_STORE_SK,S_MARKET_ID | 0.011612746 |
SS_CUSTOMER_SK,SS_TICKET_NUMBER | 0.000101299 |
SS_CUSTOMER_SK,SS_STORE_SK | 0.000000000 |
相関係数分析
相関ペア | 係数 | 妥当性 | 期待範囲 | 確認ポイント | 影 響 |
検討事項 |
---|---|---|---|---|---|---|
DISCOUNT - COUPON |
0.999 | 高※ | 中程度? | ※値引 =クーポンの疑い |
低 | 値引種別確認 |
NET_PAID - NET_PAID_TAX |
0.999 | 高 | 高い (税率) |
税率の一貫性 計算の正確性 |
低 | 異常値監視 税率変更時確認 |
WHOLESALE - LIST_PRICE |
0.958 | 高 | 高め (価格設定) |
カテゴリ別差異 マージン方針 |
中 | カテゴリ分析 価格戦略確認 |
SALES - EXT_SALES |
0.764 | 中 | 中~の想定 | 大口注文影響? 数量割引効果 特別価格の有無 |
中 | 数量分析 価格帯分析 |
TAX - NET_PAID | 0.780 | 中 | 中~の想定 | 複数税率存在 非課税商品混在 |
中 | 税率体系確認 商品区分確認 |
QUANTITY - PROFIT |
0.272 | 高 | 低~中程度 | 数量割引施策 在庫調整影響 |
低 | 施策効果分析 傾向監視 |
LIST - PROFIT |
0.172 | 高 | 低~中程度 (複合要因) |
値引施策影響 コスト変動 |
低 | 利益構造分析 傾向監視 |
SS_STORE_SK - S_MARKET_ID |
0.012 | 高 | ゼロに近い (独立採番) |
採番規則 ID体系独立性 |
低 | 体系維持確認 |
SS_CUSTOMER_SK - SS_TICKET_NUMBER |
0.000 | 高 | ゼロ (完全独立) |
採番の独立性 システム設計 |
低 | 定期的確認 |
SS_CUSTOMER_SK - SS_STORE_SK |
0.000 | 高 | ゼロ (完全独立) |
ID体系独立性 データ設計 |
低 | 定期的確認 |
合成データの品質評価総括
1. データ特性の評価
基本特性の維持
評価項目 | 評価 | 所見 |
---|---|---|
分布特性 | 良好 | • 基本統計量の高精度な維持(差異1.3%以内) • カテゴリ分布の適切な再現(差異0.6%以内) |
整合性 | 良好 | • ID体系の独立性保持 • マスタ参照関係の維持 • 業務ロジックの反映 |
現実性 | 良好 | • 妥当な値域での生成 • 極端な異常値の抑制 • 実在性の高いデータ |
データ間関係性
関係性 | 評価 | 所見 |
---|---|---|
弱い相関 | 良好 | • 独立性が適切に保持 • 基本的な傾向の維持 |
強い相関 | 要注意 | • 完全な相関関係の維持は困難 • 特にミクロな分析での制約 |
計算関係 | 中程度 | • 基本的な計算整合性は維持 • 複雑な計算関係で一部乖離 |
2. プライバシー保護の評価
保護機能の有効性
- 自動検知: 電子メール、IDなどの基本的な個人情報を適切に検知
- マスキング: 検知項目に対する適切なマスキング処理
- 新規生成: プライバシーを考慮した代替データの生成
要注意点
- 名前などの一部個人情報が自動検知から漏れる可能性
- 明示的な個人情報指定の必要性
- 用途に応じた追加的な保護措置の検討
データの確認は出来ましたので、データの品質面に着目し、より詳細な評価をしていこうと思います
3. 合成データの分析と評価
元データと合成データの比較をすることで、合成データの有用性の確認をしたいと思います
前提条件
snowflakeの合成ストアドプロシージャやそこで用いられるコピュラの制約が重要な前提事項となるのでそれを踏まえた現実的な判断をしたいと思います
Snowflakeストアドプロシージャの特性(制御の制約)
- パラメータ調整の自由度が限定的
- コピュラで実行されるぐらいしか情報がない(処理の透明性と予測可能性に制限)
コピュラの特性(アルゴリズム上の制約)
- 多次元の依存構造を表現可能
- 個別の周辺分布は保持
- 強い相関(0.9以上)の正確な再現は期待できない
- 完全な相関関係の維持は技術的に困難
3.1 分析アプローチ
-
相関分析(Query 1)
- 変数間の関係性保持度を評価
- 特に経済的関連性の維持状況を確認
-
数値分布分析(Query 2)
- 連続変数の分布特性を評価
- 平均、標準偏差、四分位範囲で類似性を確認
-
カテゴリカル分布分析(Query 3)
- 離散変数の分布保持度を評価
- 各カテゴリの比率の類似性を確認
3.2 元データとの比較
検証用の元データと生成した合成データを比較するためのクエリを用意しました
実行クエリ(長いので折りたたみ)
-- 1. 相関関係の詳細分析(相関係数の比較)
WITH correlation_pairs AS (
-- オリジナルデータの相関係数計算
SELECT
'Original' as data_source,
'Income-Amount' as correlation_pair,
corr(cd.income_level, cp.amount) as correlation_value
FROM CUSTOMER_DATA_2 cd
JOIN CUSTOMER_PURCHASE cp ON cd.customer_id = cp.customer_id
UNION ALL
SELECT
'Original' as data_source,
'Age-Income' as correlation_pair,
corr(age, income_level) as correlation_value
FROM CUSTOMER_DATA_2
UNION ALL
SELECT
'Original' as data_source,
'Age-Purchase' as correlation_pair,
corr(cd.age, cp.amount) as correlation_value
FROM CUSTOMER_DATA_2 cd
JOIN CUSTOMER_PURCHASE cp ON cd.customer_id = cp.customer_id
UNION ALL
-- 合成データの相関係数計算
SELECT
'Synthetic' as data_source,
'Income-Amount' as correlation_pair,
corr(cd.income_level, cp.amount) as correlation_value
FROM SYNTHETIC_CUSTOMER_DATA_2 cd
JOIN SYNTHETIC_CUSTOMER_PURCHASE cp ON cd.customer_id = cp.customer_id
UNION ALL
SELECT
'Synthetic' as data_source,
'Age-Income' as correlation_pair,
corr(age, income_level) as correlation_value
FROM SYNTHETIC_CUSTOMER_DATA_2
UNION ALL
SELECT
'Synthetic' as data_source,
'Age-Purchase' as correlation_pair,
corr(cd.age, cp.amount) as correlation_value
FROM SYNTHETIC_CUSTOMER_DATA_2 cd
JOIN SYNTHETIC_CUSTOMER_PURCHASE cp ON cd.customer_id = cp.customer_id
)
SELECT
cp1.correlation_pair,
cp1.correlation_value as original_correlation,
cp2.correlation_value as synthetic_correlation,
ABS(cp1.correlation_value - cp2.correlation_value) as correlation_difference,
CASE
WHEN ABS(cp1.correlation_value - cp2.correlation_value) <= 0.1 THEN '高'
WHEN ABS(cp1.correlation_value - cp2.correlation_value) <= 0.3 THEN '中'
ELSE '低'
END as similarity_level
FROM correlation_pairs cp1
JOIN correlation_pairs cp2
ON cp1.correlation_pair = cp2.correlation_pair
AND cp1.data_source = 'Original'
AND cp2.data_source = 'Synthetic'
ORDER BY correlation_difference DESC;
-- 2. 分布の類似性分析(数値データ)
WITH stats_comparison AS (
-- オリジナルデータの統計量
SELECT
'Age' as metric,
'Original' as data_source,
AVG(age) as mean,
STDDEV(age) as std_dev,
PERCENTILE_CONT(0.25) WITHIN GROUP (ORDER BY age) as p25,
PERCENTILE_CONT(0.75) WITHIN GROUP (ORDER BY age) as p75
FROM CUSTOMER_DATA_2
UNION ALL
SELECT
'Income' as metric,
'Original' as data_source,
AVG(income_level) as mean,
STDDEV(income_level) as std_dev,
PERCENTILE_CONT(0.25) WITHIN GROUP (ORDER BY income_level) as p25,
PERCENTILE_CONT(0.75) WITHIN GROUP (ORDER BY income_level) as p75
FROM CUSTOMER_DATA_2
UNION ALL
-- 合成データの統計量
SELECT
'Age' as metric,
'Synthetic' as data_source,
AVG(age) as mean,
STDDEV(age) as std_dev,
PERCENTILE_CONT(0.25) WITHIN GROUP (ORDER BY age) as p25,
PERCENTILE_CONT(0.75) WITHIN GROUP (ORDER BY age) as p75
FROM SYNTHETIC_CUSTOMER_DATA_2
UNION ALL
SELECT
'Income' as metric,
'Synthetic' as data_source,
AVG(income_level) as mean,
STDDEV(income_level) as std_dev,
PERCENTILE_CONT(0.25) WITHIN GROUP (ORDER BY income_level) as p25,
PERCENTILE_CONT(0.75) WITHIN GROUP (ORDER BY income_level) as p75
FROM SYNTHETIC_CUSTOMER_DATA_2
)
SELECT
s1.metric,
s1.mean as original_mean,
s2.mean as synthetic_mean,
ABS(s1.mean - s2.mean) / s1.mean * 100 as mean_diff_pct,
s1.std_dev as original_std,
s2.std_dev as synthetic_std,
ABS(s1.std_dev - s2.std_dev) / s1.std_dev * 100 as std_diff_pct,
ABS(s1.p75 - s1.p25) as original_iqr,
ABS(s2.p75 - s2.p25) as synthetic_iqr,
CASE
WHEN ABS(s1.mean - s2.mean) / s1.mean <= 0.05 THEN '高'
WHEN ABS(s1.mean - s2.mean) / s1.mean <= 0.15 THEN '中'
ELSE '低'
END as distribution_similarity
FROM stats_comparison s1
JOIN stats_comparison s2
ON s1.metric = s2.metric
AND s1.data_source = 'Original'
AND s2.data_source = 'Synthetic'
ORDER BY mean_diff_pct DESC;
-- 3. カテゴリカルデータの分布比較
WITH category_distribution AS (
-- オリジナルデータの分布
SELECT
'Gender' as category_type,
gender as category_value,
'Original' as data_source,
COUNT(*) as count,
COUNT(*) * 100.0 / SUM(COUNT(*)) OVER (PARTITION BY 'Gender') as percentage
FROM CUSTOMER_DATA_2
GROUP BY gender
UNION ALL
SELECT
'Residence' as category_type,
residence_area as category_value,
'Original' as data_source,
COUNT(*) as count,
COUNT(*) * 100.0 / SUM(COUNT(*)) OVER (PARTITION BY 'Residence') as percentage
FROM CUSTOMER_DATA_2
GROUP BY residence_area
UNION ALL
-- 合成データの分布
SELECT
'Gender' as category_type,
gender as category_value,
'Synthetic' as data_source,
COUNT(*) as count,
COUNT(*) * 100.0 / SUM(COUNT(*)) OVER (PARTITION BY 'Gender') as percentage
FROM SYNTHETIC_CUSTOMER_DATA_2
GROUP BY gender
UNION ALL
SELECT
'Residence' as category_type,
residence_area as category_value,
'Synthetic' as data_source,
COUNT(*) as count,
COUNT(*) * 100.0 / SUM(COUNT(*)) OVER (PARTITION BY 'Residence') as percentage
FROM SYNTHETIC_CUSTOMER_DATA_2
GROUP BY residence_area
)
SELECT
cd1.category_type,
cd1.category_value,
cd1.count as original_count,
cd2.count as synthetic_count,
cd1.percentage as original_pct,
cd2.percentage as synthetic_pct,
ABS(cd1.percentage - cd2.percentage) as percentage_diff,
CASE
WHEN ABS(cd1.percentage - cd2.percentage) <= 2 THEN '高'
WHEN ABS(cd1.percentage - cd2.percentage) <= 5 THEN '中'
ELSE '低'
END as distribution_similarity
FROM category_distribution cd1
JOIN category_distribution cd2
ON cd1.category_type = cd2.category_type
AND cd1.category_value = cd2.category_value
AND cd1.data_source = 'Original'
AND cd2.data_source = 'Synthetic'
ORDER BY cd1.category_type, percentage_diff DESC;
それぞれの出力結果は以下となります
相関関係の詳細分析
CORRELATION_PAIR | ORIGINAL_CORRELATION | SYNTHETIC_CORRELATION | CORRELATION_DIFFERENCE | SIMILARITY_LEVEL |
---|---|---|---|---|
Income-Amount | 0.9684152022 | 0.001746622083 | 0.9666685801 | 低 |
Age-Purchase | -0.001484836076 | 0.000929684363 | 0.002414520439 | 高 |
Age-Income | -0.002199985128 | -0.001836627765 | 0.0003633573624 | 高 |
分布の類似性分析
METRIC | ORIGINAL_MEAN | SYNTHETIC_MEAN | MEAN_DIFF_PCT | ORIGINAL_STD | SYNTHETIC_STD | STD_DIFF_PCT | ORIGINAL_IQR | SYNTHETIC_IQR | DISTRIBUTION_SIMILARITY |
---|---|---|---|---|---|---|---|---|---|
Income | 5.505310 | 5.434635 | 1.283760587500 | 4.500019333 | 4.498212534 | 0.04015092543 | 9.000 | 9.000 | 高 |
Age | 49.048830 | 48.790204 | 0.527282709900 | 18.194599089 | 18.305728311 | 0.6107813743 | 32.000 | 32.000 | 高 |
カテゴリカルデータの分布比較
CATEGORY_TYPE | CATEGORY_VALUE | ORIGINAL_COUNT | SYNTHETIC_COUNT | ORIGINAL_PCT | SYNTHETIC_PCT | PERCENTAGE_DIFF | DISTRIBUTION_SIMILARITY |
---|---|---|---|---|---|---|---|
Gender | Other | 49763 | 48535 | 49.763000 | 49.772340 | 0.009340 | 高 |
Gender | Female | 50237 | 48979 | 50.237000 | 50.227660 | 0.009340 | 高 |
Residence | South | 25086 | 23917 | 25.086000 | 24.526735 | 0.559265 | 高 |
Residence | East | 25121 | 24969 | 25.121000 | 25.605554 | 0.484554 | 高 |
Residence | North | 24819 | 24275 | 24.819000 | 24.893861 | 0.074861 | 高 |
Residence | West | 24974 | 24353 | 24.974000 | 24.973850 | 0.000150 | 高 |
3.3 総合評価
それぞれの出力結果について考察してみます
分析観点 | 評価項目 | 結果 | 評価 | 影響度 | 活用方針 |
---|---|---|---|---|---|
数値変数分布 (連続値) |
平均値の差異 | 1.3%以下 | 優良 | 低 | 基本統計量として そのまま活用可 |
標準偏差の差異 | 1%未満 | 優良 | 低 | 分散分析等に 活用可 |
|
IQR | 完全一致 | 優良 | 低 | 四分位分析に 適用可 |
|
カテゴリ変数 (離散値) |
性別分布 | 差異0.01%未満 | 優良 | 低 | 属性分析に 直接活用可 |
地域分布 | 差異0.6%未満 | 優良 | 低 | 地域分析に 直接活用可 |
|
弱い相関関係 (0.3未満) |
年齢-収入 | 差異0.0004 | 優良 | 低 | 独立性分析に 活用可 |
年齢-購買 | 差異0.002 | 優良 | 低 | トレンド分析に 活用可 |
|
強い相関関係 (0.7以上) |
収入-金額 | 差異0.967 | 要注意 | 高 | 経済分析では 使用制限必要 |
税-支払額 | 差異0.776 | 注意 | 中 | 補完データとして 限定利用 |
評価基準:
- 優良:元データとの差異が1%未満
- 良好:差異が1-5%
- 注意:差異が5-50%
- 要注意:差異が50%超
影響度基準:
- 低:一般的な分析に影響なし
- 中:一部の詳細分析に影響
- 高:特定領域の分析に大きな影響
この評価表から導かれる総合的な見解:
- 基本的な統計量や分布特性は高精度で維持
- カテゴリカルデータの再現性は非常に高い
- 弱い相関関係は適切に保持
- 強い相関関係の維持には技術的な制約あり(コピュラの限界か)
4. 合成データの活用可能性と展望
4.1 推奨される活用シーン
用途 | 現状の強み | 活用のポイント | 今後の可能性 |
---|---|---|---|
開発・ テスト |
基本分布の高精度な再現 プライバシー保護の確保 |
テストデータへ即活用可能 本番相当の検証環境構築 |
より複雑な データパターンへの対応 |
基礎分析 | 単一変数の特性維持 カテゴリ分布の再現 |
顧客属性分析 セグメント分析 |
時系列分析等への応用 |
データ共有 | プライバシーリスクの低減 データ活用の促進 |
部門間での安全な共有 外部連携での活用 |
より広範な 共有シーンでの活用 |
4.2 今後の期待
1. 技術面での進化
- 変数間の関係性表現の強化
- より複雑なパターンの学習
- 新しいデータタイプへの対応
2. 活用シーンの広がり
- より高度な分析への適用
- 新しいユースケースの発見
- 既存機能との連携強化
まとめ
Snowflakeの合成データ機能は、プレビュー段階ながら基本的な統計特性の維持に優れており、特に開発環境やシンプルな分析での即時活用が可能です。
現時点での制約(強い相関の維持など)はありますが、それらは今後の発展により緩和されていく可能性が高く、むしろ期待が持てる部分と言えます。
それらを考慮するとプライバシーを考慮したデータ活用の新しい選択肢として、その発展が楽しみな機能と言えそうです。
第二章のまとめ
Snowflakeは、プライバシー保護を実現するためにさまざまな機能を提供しており、それらは強力で柔軟なプライバシー保護を実現できるものです。 ただし、自社のデータが複雑化し、詳細化していく中で、プライバシー保護の取り組みもさらに高度化していく必要があります。
第一章では個々のプライバシー保護機能の紹介をさせていただき、第二章ではプレビューながら、合成データ機能について紹介させていただきました。第三章では、各機能の組み合わせに加え、Snowflakeが新たに一般提供した差分プライバシーという機能も踏まえた設計例を紹介させていただこうと思います。(現在執筆中です)
毎度長文で読みづらくて申し訳ない気もしますが、自分で振り返る時に、我ながら1記事で情報がまとまっているので、便利に使っている事もあり、お付き合いいただければと思います!
Discussion