🐡

再現性を担保したAWS Athenaでのランダムサンプリングについて(Advent Calendar Day 4)

はじめに

こんにちは、D2Cデータサイエンティストの小林です。

本記事では、AWS Athenaによるハッシュ関数を用いた再現性のあるサンプリング手法について検討します。

ハッシュについては以前の記事をご覧ください。
また、AWS AthenaでのDB作成やテーブル作成については触れませんので別の記事を参考にしていただければと思います。

開発環境

検証において以下の環境を使用しました。

AWS EC2 (インスタンスタイプ: r5.xlarge)
Python 3.10系(3.10.9)
awswrangler 2.6.0
pandas 1.5.1
random 3.10系で提供されているモジュール
string 3.10系で提供されているモジュール

ランダムサンプリングとは

ランダムサンプリングとは、無作為抽出とも呼ばれ、あるデータの中からランダムにデータの一部(サンプル)を抽出する方法のことです。
データ数が膨大な場合に対してよく用いられます。
ランダムサンプリングを適切に行えれば、膨大なデータの性質を一部のデータを調べるだけで把握することも可能です。
ただし、データ抽出に人間の意思や何かしらの意図が絡んでしまうと、適切な抽出を行えず分析の質が落ちてしまう可能性やランダムサンプリングしたデータに対する分析結果と、データ全てに対して分析を行った結果に誤差が生じる可能性があります。

再現性を担保してサンプリングする意味

上記で述べたように、データ分析をする際に、一部のデータから性質をみることがあります。
このような分析をする際に、何度抽出をしても同じ結果となるよう再現性が必要となる場合があります。
弊社では、機械学習を行う際に AWS Athenaを使用してデータを抽出することがあります。
この際に、ダウンサンプリングを行なった状態でデータを取得することがあります。
AthenaでランダムにデータサンプリングするSQLとしていくつかありますが、こちらは再現性がなくSQLを実行するたびに抽出されるデータ、件数が変わってしまいます。
このような場合、実験や検証の際に毎回結果が異なり正しい評価ができないことがあります。
もちろん、Athenaでデータを全て抽出しPythonなどで加工しSEEDを決めてサンプリングすれば再現性は担保されますが、データが膨大な場合Athenaで抽出する際にダウンサンプリングされていると実験が捗る場合があります。

よって、今回はAthenaで再現性のあるサンプリング手法について検討したいと思います。

実装と検証

サンプルデータの生成

import awswrangler as wr
import pandas as pd
import random, string

random.seed(818) # 乱数シードを818に設定

def randomname(n):
    randlst = [random.choice(string.ascii_letters + string.digits) for i in range(n)]
    return ''.join(randlst)

user_ids = []
age = []
gender = []
for i in range(0, 107):
    user_ids.append(randomname(40))
    age.append(random.randint(18, 80))
    gender.append(random.randint(0, 2)) ### 0: 女性, 1: 男性, 2: 不明 
    
### データフレームの作成
df = pd.DataFrame()
df["user_id"] = user_ids
df["age"] = age
df["gender"] = gender

### データの保存
df.to_parquet("sample.parquet")

上記データをAWS S3に保存し、Athenaで使えるようにします。
テーブルDDLは以下になります。
(db, prefix は適当な箇所を指定する必要があります。)

CREATE EXTERNAL TABLE `sample`(
  `user_id` string, 
  `age` int, 
  `gender` int)
ROW FORMAT SERDE 
  'org.apache.hadoop.hive.ql.io.parquet.serde.ParquetHiveSerDe' 
STORED AS INPUTFORMAT 
  'org.apache.hadoop.hive.ql.io.parquet.MapredParquetInputFormat' 
OUTPUTFORMAT 
  'org.apache.hadoop.hive.ql.io.parquet.MapredParquetOutputFormat'
LOCATION
  's3://db/prefix'

Athenaによるランダムサンプリング手法1

query = '''
   /* データの10%をランダムに取得するSQL */
   SELECT 
       * 
   FROM 
       sample
   tablesample bernoulli(10)
'''  
df=wr.athena.read_sql_query(query, database=DATABASE, ctas_approach=False) ### 適当なDATABASEを指定

print(df)
print(len(df))

こちらを実行するとデータの10%をランダムに取得することができます。
しかし、実行のたびにデータと件数が変わってしまいます。

Athenaによるランダムサンプリング手法2

query = '''
    WITH
    sample_table AS (
        SELECT
            *,
            RANDOM() AS rnd
        FROM 
            sample
    )
    SELECT
        *
    FROM
        sample_table
    ORDER BY
        rnd
    limit 10
'''  
df=wr.athena.read_sql_query(query, database=DATABASE, ctas_approach=False) ### 適当なDATABASEを指定

print(df)
print(len(df))

こちらを実行するとデータを10件(limitで指定した件数)ランダムに取得することができます。
しかし、実行のたびにデータが変わってしまいます。
データが変わってしまう原因として、RANDOM() AS rndの値が毎回変わってしまうことが挙げられます。
このrndの値がランダムに決まるが実行のたびに変わらないようにすることで再現性を担保したランダムな抽出ができます。

そこで、このrndの値をハッシュ関数を用いることで毎回データが変わることを防ぎます。

Athenaによるランダムサンプリング手法3

query = '''
    WITH
    sample_table AS (
        SELECT
            *,
            from_big_endian_64(
                xxhash64(CAST(user_id || '818' AS varbinary)) /*818: SEED*/
            ) AS hash_rnd
        FROM 
            sample
    )
    SELECT
        *
    FROM
        sample_table
    ORDER BY
        hash_rnd
    limit 10
'''  
df=wr.athena.read_sql_query(query, database=DATABASE, ctas_approach=False) ### 適当なDATABASEを指定

print(df)
print(len(df))

何度、実行しても結果が同じになると思います。
※ハッシュ化させるキーはユニークである必要がある。また、ハッシュの衝突についても考慮する必要がある。
Athenaにおけるハッシュ関数について詳しく知りたい方はこちらを参照してください。

まとめ

今回は、AWS Athenaでの再現性を担保したランダムサンプリングの手法について検討しました。
Athenaによるランダムサンプリング手法3で紹介した手法を用いることで再現性を担保することができます。
本記事が、Athenaを用いてデータを抽出する際の参考になれば幸いです。

また、他にもより良いやり方があると思いますので、ぜひコメント欄で教えていただければと思います。

最後までお読みいただきありがとうございました。

参考

https://qiita.com/nabion/items/46c65aaf22e0dfb21356
https://codeseterpie.com/blog/atb4ymiuk/
https://docs.aws.amazon.com/ja_jp/athena/latest/ug/functions.html

採用情報

  • D2Cグループ採用サイト

https://recruit.d2c.co.jp/

  • D2C問い合わせフォーム

https://www.d2c.co.jp/inquiryform/

D2C m-tech

Discussion