qtatsuの週報

初心者ですわぁ

pandasのDataFrameとDynamoDBの相互変換

はじめに

無理矢理感があるので、あくまでこういう方法でもできる、という程度の個人的な覚書です。

  1. DataFrameで持っているデータをそのままDynamoDBに突っ込む
  2. DynamoDBのデータをDataFrameに入れる

この二つをboto3を使って行います。

前提として

DataFrameで持っているデータをDynamoDBにput_itemする

以下の様なDataFrameがあるとします。ポイントとして

  • NaNが入っている
  • 各レコードをdictとし、そのリストの形にしたい
In [175]: df
Out[175]:
     name          title             year                        info
0    レミリア  東方紅魔郷  2002   {'spell_card': ['紅色の幻想郷']}
1    博麗霊夢    NaN           2002                         NaN
2    博麗霊夢  東方妖々夢  2003                         NaN
3    博麗霊夢  東方永夜抄  2004                         NaN
# tableの準備
import boto3
dynamodb = boto3.resource('dynamodb', region_name='ap-northeast-1')
table = dynamodb.Table('Character')


import numpy as np
import pandas as pd

# orient='records' がポイントです。list of dictになります。
data = df.to_dict(orient='records')

with table.batch_writer() as batch:
    for item in data:
        # ここで、NaNが入っているkeyを落とします。nanのままだとエラーになります。
        item_not_has_nan = {key: item[key] for key in item if item[key] is not np.nan}
        batch.put_item(Item=item_not_has_nan)

DynamoDBのデータをDataFrameに入れる

そのまま入れられます。

ret = table.scan()
df = pd.DataFrame(data=ret['Items'])

df
     name  title  year                        info
0    レミリア  東方紅魔郷  2002  {'spell_card': ['紅色の幻想郷']}
1    博麗霊夢    NaN  2002                         NaN
2    博麗霊夢  東方妖々夢  2003                         NaN
3    博麗霊夢  東方永夜抄  2004                         NaN

おまけ: 取得するattributeを指定する

DataFrameにした後でも加工は可能ですが、取得したいAttributeが決まっているなら基本的にはDynamoDB側で落とす方がいいと思います。

以下ではname, titleのみ取得しています。ただし、nameはdynamoDBの予約語です。ですので、一度変数(#n)を指定してから、別の引数でそれを置換するような書き方(下記)が必要です。

ret = table.scan(ProjectionExpression="#n, title", ExpressionAttributeNames={'#n': 'name'})

pd.DataFrame(data=ret['Items'])

     name  title
0    レミリア  東方紅魔郷
1    博麗霊夢    NaN
2    博麗霊夢  東方妖々夢
3    博麗霊夢  東方永夜抄
4  フランドール  東方紅魔郷