Multilingual Amazon Reviews Corpus (MARC) は Amazon Science によって公開された多言語のレビューコーパスです.このコーパスには,2015年から2019年にかけて収集された英語,日本語,ドイツ語,フランス語,スペイン語,中国語のレビューが含まれています.元々 AWS S3 で公開されていたデータセットの各レコードには,レビュー本文,レビュータイトル,星評価,匿名化されたレビューアID,匿名化された製品ID,製品カテゴリ(「書籍」,「家電」など)が含まれていました.しかしながら,2025年時点ではすでに AWS S3 での公開は取りやめになっているようです.
したがって,ここでは Hugging Face 上で公開されている SetFitによる日本語レビューに特化したデータセット (https://huggingface.co/datasets/SetFit/amazon_reviews_multi_ja) を利用する方法を示します.このデータは JSON 形式でレビュー本文とラベル情報(0〜4の星評価)などが含まれています.形態素解析や分類タスクにもすぐに使えるフォーマットになっており,日本語の自然言語処理研究に適しています.なお,このデータは20万件の訓練データ,5千件の検証データ,5千件のテストデータ(合計21万件)からなります.
実際上, SetFitデータセット (https://huggingface.co/datasets/SetFit/amazon_reviews_multi_ja) のページにデータセットの利用方法が掲載されているので,そこを参照すると意外と簡単に利用できるのではないでしょうか.
まず,dataset ライブラリがインストールされていることを pip list コマンドで確認します.インストールされていなければ,次のコマンドでインストールしてください.
pip install datasets
Jupyter Lab で次のコードを実行するとデータセットがダウンロードされます.
from datasets import load_dataset
import pandas as pd
ds = load_dataset("SetFit/amazon_reviews_multi_ja")
ダウンロードしたデータセットが ds に格納されているので,その内容を確認します.この結果を見ると,train,validation,test という3つのデータに分割されていることが分かります.
ds
DatasetDict({
train: Dataset({
features: ['id', 'text', 'label', 'label_text'],
num_rows: 200000
})
validation: Dataset({
features: ['id', 'text', 'label', 'label_text'],
num_rows: 5000
})
test: Dataset({
features: ['id', 'text', 'label', 'label_text'],
num_rows: 5000
})
})
分割ごとに取り出しておきます.
train_ds = ds['train']
validation_ds = ds['validation']
test_ds = ds['test']
訓練データ (train_ds) だけ表示してみます.
train_ds
Dataset({
features: ['id', 'text', 'label', 'label_text'],
num_rows: 200000
})
データの各カラムについて型情報を取得してみましょう.
train_ds.features
{'id': Value('string'),
'text': Value('string'),
'label': Value('int64'),
'label_text': Value('string')}
データの件数は次のような方法で取得できます.
train_ds.num_rows
200000
次の方法でもデータの件数を取得できます.
len(train_ds)
200000
レビューデータの最初の5件を表示してみます.なお,データは評価順に並んでいることから,先頭からしばらくは0点のレビューが続きます.
train_ds[:5]
{'id': ['ja_0388536', 'ja_0701307', 'ja_0724445', 'ja_0018251', 'ja_0727421'],
'text': ['普段使いとバイクに乗るときのブーツ兼用として購入しました。見た目や履き心地は良いです。 しかし、2ヶ月履いたらゴム底が削れて無くなりました。また、バイクのシフトペダルとの摩擦で表皮が剥がれ、本革でないことが露呈しました。ちなみに防水とも書いていますが、雨の日は内部に水が染みます。 安くて見た目も良く、履きやすかったのですが、耐久性のなさ、本革でも防水でも無かったことが残念です。結局、本革の防水ブーツを買い直しました。',
'十分な在庫を用意できない販売元も悪いですが、Amazonやら楽⚪︎が転売を認めちゃってるのが結果的に転売の後押しになっちゃってるんだよなぁ… Amazonもここぞとばかりに抱き合わせ販売しまくるし… それを恥ずかしいと思えなくなったら動物と同じですよ、最大手さん。',
'見た目はかなりおしゃれで気に入りました。2、3回持ち歩いた後いつも通りゼンマイを巻いていたら突然空回り。 針の調整はできるけど、つまみをあげても下げてもゼンマイを巻くことができず。 時計屋に持って行って中を開けてもらったら、中のケースと外側の規格がそもそも合っていないため、固定されず、一度ズレると噛み合わなくなるんだそう。 返品して交換した方がいいと言われましたが、保証書付いてないし、 クーリングオフ期間もとっくに過ぎています。 アンティーク感覚で家で放置するならおススメですが、 本来の用途としては全く使えません。 ご注意を。',
'よくある部分での断線はしませんでした ただiphoneとの接続部で接触不良、折れました iphoneの中に残されてしまい摘出に苦労しました',
'プラモデルの塗装剥離に使う為に購入 届いて早速使ってみた 結果 1ヶ月経っても未だに剥離出来ない 何じゃこら!'],
'label': [0, 0, 0, 0, 0],
'label_text': ['0', '0', '0', '0', '0']}
最後の5件のレビューデータを表示します.最後は4点のデータになっています.
train_ds[-5:]
{'id': ['ja_0305811', 'ja_0029881', 'ja_0605542', 'ja_0836956', 'ja_0027532'],
'text': ['初孫の為に購入しました。近所におもちゃ屋さんがなく、ベビー服のお店にあるかと思ったのですが、なかなか売っていないのですね。ポロンちゃんは父親になった息子が赤ん坊の時一番気に入っていたおもちゃです。ベットの隅のお人形を泣いているときも機嫌の良い時もボカンボカンしていました。 思いで深いおもちゃを孫に買ってあがたくてアマゾンで見つけて注文しました。真っ赤のポロンちゃんでした。孫は3か月になったばかりですが、キックして遊びます。おきあがりこぼしのアンパンマンもありましたが中国製。赤ちゃんがなめるかもしれないですし、日本製のおもちゃのが安心ですね。',
'よかったです!見た目も可愛い!ラインが入っているのが特に気に入りました。シンプル可愛い感じですね。',
'美味しい料理が、ポイントを押さえて、できます。イタリアンを作ってみたい…けど、難しそうと思ってる、方にオススメです。',
'取り付け簡単 値段も安い 明るい',
'私はよく私のfacebookの上で私が買った良いものをお勧めしますが、今回も強くお勧めします。'],
'label': [4, 4, 4, 4, 4],
'label_text': ['4', '4', '4', '4', '4']}
特定のカラムだけ(ここでは,レビューテキストだけ)を先頭から5件取り出してみます.
train_ds["text"][:5]
['普段使いとバイクに乗るときのブーツ兼用として購入しました。見た目や履き心地は良いです。 しかし、2ヶ月履いたらゴム底が削れて無くなりました。また、バイクのシフトペダルとの摩擦で表皮が剥がれ、本革でないことが露呈しました。ちなみに防水とも書いていますが、雨の日は内部に水が染みます。 安くて見た目も良く、履きやすかったのですが、耐久性のなさ、本革でも防水でも無かったことが残念です。結局、本革の防水ブーツを買い直しました。', '十分な在庫を用意できない販売元も悪いですが、Amazonやら楽⚪︎が転売を認めちゃってるのが結果的に転売の後押しになっちゃってるんだよなぁ… Amazonもここぞとばかりに抱き合わせ販売しまくるし… それを恥ずかしいと思えなくなったら動物と同じですよ、最大手さん。', '見た目はかなりおしゃれで気に入りました。2、3回持ち歩いた後いつも通りゼンマイを巻いていたら突然空回り。 針の調整はできるけど、つまみをあげても下げてもゼンマイを巻くことができず。 時計屋に持って行って中を開けてもらったら、中のケースと外側の規格がそもそも合っていないため、固定されず、一度ズレると噛み合わなくなるんだそう。 返品して交換した方がいいと言われましたが、保証書付いてないし、 クーリングオフ期間もとっくに過ぎています。 アンティーク感覚で家で放置するならおススメですが、 本来の用途としては全く使えません。 ご注意を。', 'よくある部分での断線はしませんでした ただiphoneとの接続部で接触不良、折れました iphoneの中に残されてしまい摘出に苦労しました', 'プラモデルの塗装剥離に使う為に購入 届いて早速使ってみた 結果 1ヶ月経っても未だに剥離出来ない 何じゃこら!']
ランダムにシャッフルして5件を取り出してみます.このとき,seed には任意の値を指定してください.なお,seedに関する説明はここを参照してください.
train_ds_shuffled = train_ds.shuffle(seed=99).select(range(5))
train_ds_shuffled[:]
{'id': ['ja_0038106', 'ja_0009643', 'ja_0814069', 'ja_0754909', 'ja_0203299'],
'text': ['沢山あげると太りますが 少量で予防になると思います 定期便にしています',
'墨入れなど細かく入っているがはみ出しや、ずれが多い、造形的には申し分無し。',
'コントローラーに接続されているケーブルが切れてきました。 劣化ですか。 ちょっとガッカリです。 保証も流石に2年だと微妙だと思うので新しく買います。',
'リバーシブルは可愛い 元のチェーンがもう少し長いほうがよかった',
'安くても 良い品物でした。良かったです。'],
'label': [4, 2, 1, 0, 4],
'label_text': ['4', '2', '1', '0', '4']}
乱数の seed を指定しなければ,実行するたびに異なる結果が得られることでしょう.
train_ds_shuffled = train_ds.shuffle().select(range(5))
train_ds_shuffled[:]
{'id': ['ja_0897623', 'ja_0548590', 'ja_0162459', 'ja_0651992', 'ja_0879009'],
'text': ['ボンボンと雪の結晶は華やかにしてくれました。 葉っぱのオーナメントは思ったより安っぽいものでしたが、形がかわいかったので形を真似させていただいて作りました。',
'思ってたより、安い匂い。 もっと純粋にローズの香りがするのかと 思ってたので使用してません。',
'カメラ付近の気泡が取れないのが非常に残念 バンパーを付けることを考えるとサイズはいい感じ',
'本品はあくまで「本物」を追求した結果です。より月光に近い光の光源を使用した。',
'早々の配送ありがとうございました。見た目は思っていた通りでした。'],
'label': [2, 1, 1, 4, 2],
'label_text': ['2', '1', '1', '4', '2']}
データセットを Pandas のデータフレームに変換する方法も至って簡単です.
train_df = train_ds.to_pandas()
validation_df = validation_ds.to_pandas()
test_df = test_ds.to_pandas()
訓練データのデータフレームを表示します.
train_df
検証データのデータフレームを表示します.
validation_df
テストデータのデータフレームを表示します.
test_df
Pandas のデータフレームにレビューデータを取り込むことができたので,様々な分析に利用できるでしょう.しかしながら,分析の前に念のため,星ごとの評価数を確認しておきます.これは Pandas のグループ化を利用すると簡単に調べることができます.まず,訓練データを評価 (label) でグループ化し,データの件数を確認します.各評価について,4万件のレビューデータが存在することが分かります.
print(train_df.groupby('label').count())
id text label_text
label
0 40000 40000 40000
1 40000 40000 40000
2 40000 40000 40000
3 40000 40000 40000
4 40000 40000 40000
検証データとテストデータについても同じように確認します.いずれも,星ごとに千件のレビューデータがあることが分かりました.
print(validation_df.groupby('label').count())
id text label_text
label
0 1000 1000 1000
1 1000 1000 1000
2 1000 1000 1000
3 1000 1000 1000
4 1000 1000 1000
print(test_df.groupby('label').count())
id text label_text label 0 1000 1000 1000 1 1000 1000 1000 2 1000 1000 1000 3 1000 1000 1000 4 1000 1000 1000
なお,macOS でも Windows であっても,ダウンロードしたデータはホームディレクトリ直下の .cache/huggingface/ にキャッシュとして保存されます.合計で200MB弱が消費されているようです.