❄️

データエンジニア向けSnowflakeプライバシー保護機能②合成データ

2024/11/10に公開

はじめに

データ駆動型の意思決定がビジネスの重要な要素となる中、プライバシー保護とデータ活用の両立は多くの組織にとって重要な課題となっています。前回の記事では、Snowflakeのプライバシー保護の各機能について解説しました。

https://zenn.dev/taro_cccmkhd/articles/8c1a3ebcc9464a

2024年10月28日、Snowflakeは新たなプライバシー保護機能として合成データ生成機能をプレビューリリースしました。この機能の追加により、Snowflakeのプライバシー保護機能は、アクセス制御やデータマスキングといった従来の保護手法に加え、より積極的なデータ活用を可能にする選択肢を提供しています。

プレビュー機能として提供される本機能は、開発環境でのテストデータ生成や、プライバシーを考慮したデータ分析など、様々なユースケースでの活用が期待されます。本記事では、この新機能の検証を通じて、その特徴と活用方法について考察して内容を自分なりにまとめてみました。

https://docs.snowflake.com/en/release-notes/2024/8_41#generate-synthetic-data-new-system-stored-procedure-for-generating-synthetic-data-preview

1. 合成データの概要

1.1 技術的概要

合成データとは、実データの統計的特性を保持しながら、人工的に生成された新しいデータセットです。

Snowflakeの合成データ生成機能

snowlfakeでは、GENERATE_SYNTHETIC_DATA というストアドプロシージャにより、合成データを作成できます
このストアドプロシージャは、コピュラをベースとした機械学習技術を用いて、元データの分布や関係性を学習して新たなデータを生成します

コピュラにより、以下を実現することが期待できます

  • 個々のレコードは完全に人工的に生成
  • 統計的な特性は元データを維持
  • データ間の関連性も考慮した生成が可能

このコピュラなどの合成データに関する技術は、先日投稿した以下の記事を参考にしてください

合成データのアルゴリズムはいずれディープラーニングや生成AIレベルになることで、さらに有用度上がるのではないかと期待しています

https://zenn.dev/taro_cccmkhd/articles/526e83eff7dc1f

1.2 ビジネス上の意義

さて、生成されら合成データの活用により、以下のようなビジネス価値の提供が期待されます

  1. 開発・テスト環境での活用

    • 本番データを使用せずに現実的なテストが可能
    • セキュリティリスクの軽減
    • 開発サイクルの効率化
  2. データ分析での活用

    • プライバシーを考慮した分析環境の提供
    • データサイエンティストの早期参画
    • 探索的なデータ分析の促進
  3. コンプライアンス対応

    • 規制要件への対応
    • データ共有における新たな選択肢
    • プライバシーリスクの低減

1は分かりやすいですね。精度よりも一定レベルのデータセットが欲しいケースは多々あります
2や3はどうでしょう。プライバシーの保護と分析データとしての精度は悩ましい課題です

1.3 プライバシー保護機能との比較

上記を踏まえた従来のプライバシー保護機能と合成データの特徴を比較してみました

機能 保護レベル 実装の複雑さ 性能影響 主な使用シナリオ リスクや懸念事項
動的データマスキング 特定のユーザーや状況に応じたデータ保護 不適切な条件設定でデータ露出のリスク
行アクセスポリシー ロール別・ユーザー別のアクセス制御 ポリシーの複雑化による管理オーバーヘッド
ハッシュ化・暗号化 機密データの保存・転送時の保護 鍵管理の複雑さ、暗号化処理の遅延
セキュアビュー 必要最低限のデータアクセスの提供 設計ミスによる露出リスク、パフォーマンス低下
集計ポリシー 小規模グループに対する統計的保護 厳格すぎるポリシーによる分析の制約
投影ポリシー プライバシー項目の出力制御 設計ミスによる露出リスク
差分プライバシー 高度な匿名化と統計的有用性の両立 ノイズ追加でデータ精度が低下する可能性
合成データ 元データとの完全な分離
開発/テスト環境での利用
規制対応したデータ共有
モデルの品質管理の複雑さ
生成データの品質保証
統計的特性の検証必要性

合成データは、既存のプライバシー保護機能を補完する新たなアプローチとして位置づけられます

  • アクセス制御との関係
    より積極的なデータ活用を可能にする選択肢を提供

  • マスキング機能との関係
    データの有用性を維持しながら、より強力な保護を実現

  • 差分プライバシーとの関係
    異なるアプローチでプライバシー保護を実現する補完的な技術

2. 合成データ生成の実装

https://docs.snowflake.com/en/sql-reference/stored-procedures/generate_synthetic_data

では、生成工程に入るに辺り、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 分析アプローチ

  1. 相関分析(Query 1)

    • 変数間の関係性保持度を評価
    • 特に経済的関連性の維持状況を確認
  2. 数値分布分析(Query 2)

    • 連続変数の分布特性を評価
    • 平均、標準偏差、四分位範囲で類似性を確認
  3. カテゴリカル分布分析(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%超

影響度基準:

  • 低:一般的な分析に影響なし
  • 中:一部の詳細分析に影響
  • 高:特定領域の分析に大きな影響

この評価表から導かれる総合的な見解:

  1. 基本的な統計量や分布特性は高精度で維持
  2. カテゴリカルデータの再現性は非常に高い
  3. 弱い相関関係は適切に保持
  4. 強い相関関係の維持には技術的な制約あり(コピュラの限界か)

4. 合成データの活用可能性と展望

4.1 推奨される活用シーン

用途 現状の強み 活用のポイント 今後の可能性
開発・
テスト
基本分布の高精度な再現
プライバシー保護の確保
テストデータへ即活用可能
本番相当の検証環境構築
より複雑な
データパターンへの対応
基礎分析 単一変数の特性維持
カテゴリ分布の再現
顧客属性分析
セグメント分析
時系列分析等への応用
データ共有 プライバシーリスクの低減
データ活用の促進
部門間での安全な共有
外部連携での活用
より広範な
共有シーンでの活用

4.2 今後の期待

1. 技術面での進化

  • 変数間の関係性表現の強化
  • より複雑なパターンの学習
  • 新しいデータタイプへの対応

2. 活用シーンの広がり

  • より高度な分析への適用
  • 新しいユースケースの発見
  • 既存機能との連携強化

まとめ

Snowflakeの合成データ機能は、プレビュー段階ながら基本的な統計特性の維持に優れており、特に開発環境やシンプルな分析での即時活用が可能です。

現時点での制約(強い相関の維持など)はありますが、それらは今後の発展により緩和されていく可能性が高く、むしろ期待が持てる部分と言えます。
それらを考慮するとプライバシーを考慮したデータ活用の新しい選択肢として、その発展が楽しみな機能と言えそうです。

第二章のまとめ

Snowflakeは、プライバシー保護を実現するためにさまざまな機能を提供しており、それらは強力で柔軟なプライバシー保護を実現できるものです。 ただし、自社のデータが複雑化し、詳細化していく中で、プライバシー保護の取り組みもさらに高度化していく必要があります。

第一章では個々のプライバシー保護機能の紹介をさせていただき、第二章ではプレビューながら、合成データ機能について紹介させていただきました。第三章では、各機能の組み合わせに加え、Snowflakeが新たに一般提供した差分プライバシーという機能も踏まえた設計例を紹介させていただこうと思います。(現在執筆中です)

毎度長文で読みづらくて申し訳ない気もしますが、自分で振り返る時に、我ながら1記事で情報がまとまっているので、便利に使っている事もあり、お付き合いいただければと思います!

Discussion