pandasのDataFrameとDynamoDBの相互変換
はじめに
無理矢理感があるので、あくまでこういう方法でもできる、という程度の個人的な覚書です。
- DataFrameで持っているデータをそのままDynamoDBに突っ込む
- DynamoDBのデータをDataFrameに入れる
この二つをboto3を使って行います。
前提として
- パーティションキー: name
- ソートキー : year
- そのほかのattribute: title, info
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 フランドール 東方紅魔郷