AWSにあるJupyter NotebookからpandasでS3のファイルを読み込むときの設定




## 概要

AWSでのEC2で[Jupyter Notebook](http://jupyter.org/)を運用している場合には、以下のように`pd.read_csv()`からS3にあるデータのパスを指定して直接読み込むことができます。

```python
import pandas as pd
os.environ["AWS_ACCESS_KEY_ID"] = "XXX..."
os.environ["AWS_SECRET_ACCESS_KEY"] = "YYY..."
all_df = pd.read_csv("s3n://mybucket/path/to/dir/data.csv")
```

このとき、上記のようにAWS_ACCESS_KEY_IDとAWS_SECRET_ACCESS_KEYをあらかじめ環境変数で指定しておく必要があります。

これらの指定を毎回するのは正直言って面倒です。`import pandas as pd`などのパッケージのインポートは手癖のようになっている人は多いと思いますが、ランダムな文字列のキーを覚えられる人なんてそうそういません。それにこういったプライベートな情報はノートブックを他人に共有する際には含めたくない情報なので、そのたびに削るというのはとても非効率ですし危険です。

そこで、Jupyter Notebookで意識せずともS3のファイルにアクセスできるよう、あらかじめ設定をしておきましょう。これには幾つかやり方があるので、それぞれ紹介したいと思います。

- jupyter notebookが起動するタイミングで設定を読み込ませる
- シェルで環境変数に直接設定する
- botoのプロファイルに記載する

なお、これら3つの方法は、どれか一つだけやれば良いです。それほどpros/consがあるわけではないので、好きなやり方で問題ないと思います。

## 方法


### 方法1：jupyter notebookが起動するタイミングで設定を読み込ませる

jupyter notebookはインストールされている前提とします。

AWS_ACCESS_KEY_IDとAWS_SECRET_ACCESS_KEYの設定を`~/.ipython/profile_default/startup/`に`00_startup.ipy`というファイル名で保存します。ファイル名は自由ですが、先頭に数字を付けるとその順で実行されます。

```python
os.environ["AWS_ACCESS_KEY_ID"] = "XXX..."
os.environ["AWS_SECRET_ACCESS_KEY"] = "YYY..."
```

ファイルの配置としては以下のような感じです。

```
$ tree .ipython/profile_default/startup
.ipython/profile_default/startup
├── 00_startup.ipy
└── README
```

こうすることで、jupyter notebookが起動するタイミングで上記コマンドが実行されますので、ノートブックから`os.environ`で指定しなくてもよくなります。

### 方法2：シェルで環境変数に直接設定する

これはシェルの環境変数として設定しておく方法です。`.bash_profile`や`.zshrc`など、自身のシェルの設定ファイルに記載してシェル起動時に読み込ませるか、直にプロンプトで実行して設定します。

```sh
export AWS_ACCESS_KEY_ID=XXX...
export AWS_SECRET_ACCESS_KEY=YYY...
```

### 方法3：botoが読み込むプロファイルに記載する

pandasの裏ではbotoというPythonのAWS SDKが使われており、そのパッケージのプロファイルに直接記載する方法もあります。下記のコードを`~/.boto`というファイル名で保存します。

```
[Credentials]
aws_access_key_id = XXX...
aws_secret_access_key = YYY...
```

==追記:2016/10/03==
上記方法はboto2での方法でした。boto3では`~/.boto`も読み込まれるものの、boto3からは以下の順で読み込まれるとのことなので、aws自体のcredentialsである`~/.aws/credentials`に記載する方が、[`awscli`](https://aws.amazon.com/jp/documentation/cli/)コマンドとの設定を共有する意味でも良いかと思います。

> The mechanism in which boto3 looks for credentials is to search through a list of possible locations and stop as soon as it finds credentials. The order in which Boto3 searches for credentials is:
> 
> 1. Passing credentials as parameters in the boto.client() method
> 2. Passing credentials as parameters when creating a Session object
> 3. Environment variables
> 4. Shared credential file (~/.aws/credentials)
> 5. AWS config file (~/.aws/config)
> 6. Assume Role provider
> 7. Boto2 config file (/etc/boto.cfg and ~/.boto)
> 8. Instance metadata service on an Amazon EC2 instance that has an IAM role configured.

```
[default]
aws_access_key_id=foo
aws_secret_access_key=bar
```

- http://boto3.readthedocs.io/en/latest/guide/configuration.html

==追記終わり==

すると、pandasでS3のパスを指定したときにbotoがインポートされ、上記プロファイルが読み込まれます。([source](https://github.com/pydata/pandas/blob/master/pandas/io/s3.py))

なお、`pip install pandas`だけではbotoがdependenciesに入っていないため一緒にインストールされないので注意が必要です。利用する際は、あらかじめ`pip install boto`をしておきましょう。

## まとめ

以上のように、pandasでS3にアクセスするときには設定の方法が幾つかあります。環境構築の際に簡単にできるものばかりですので、ぜひとも設定しておきましょう。

## 補足

これらの手法はAWS上のJupyter Notebookに限らず、AWSのキーさえあればどのような環境でもS3に接続できるため、ローカルからでも同様に`pd.read_csv("s3n://...)`でデータを取得できます。ただし、S3からAWS外部へのデータの送信となり転送量が発生するので、利用の際は注意が必要です。そもそも転送時間の問題で重いデータは扱いづらいと思いますが、S3利用が前提のソースコードを違う環境で動かす際には、確認したほうがいいですね。AWSのキーをローカルではデフォルトにしておかないのが賢明かもしれません。

## 参考

- [EC2へのSpark導入とiPython Notebookの連携 - Qiita](http://qiita.com/fuppi/items/e7f06128d0c1f471b42a)
- [Using Jupyter on Apache Spark: Step-by-Step with a Terabyte of Reddit Data](http://blog.insightdatalabs.com/jupyter-on-apache-spark-step-by-step/)