DSX オブジェクト・ストレージからのCSVデータの読込み Python コード

Watson Data Platform の中核サービスの一つ [Data Science Experience](https://datascience.ibm.com/) (以下DSX) の Notebook上の Pythonコードから、オブジェクト・ストレージ上のファイルを読み出す方法についての忘備録です。


書込み用のコードは、Bluemix PaaS オブジェクト・ストレージ上のデータを DSX の Notebooks上のPythonのプログラムから読み出すためのものです、 
オプジェクトストレージは、Bluemix インフラストラクチャー の IBM Cloud Onject Storage ではなく、Bluemix PaaS のサービス上にあるオブジェクト・ストレージですから間違えない様に気おつけてくださいね。 サーバーやIoT機器などから送られたデータを一旦 Bluemix PaaS のオブジェクト・ストレージに保存しておいて、DSX の Pythonコードから読み込んで、科学計算処理を実行するコンセプトで書いたコードです。


![スクリーンショット 2017-04-20 12.04.03.png](https://qiita-image-store.s3.amazonaws.com/0/42829/09cdf774-8959-3c45-32b4-27f6c3b65a1b.png)
図1 コンセプト Data Science Experience の Notebook で動作する 本 Python コード

# 使い方解説

使い方は [DSX](https://datascience.ibm.com/) にログインして、Project -> Default Project (任意のプロジェクト名) -> Add Notebooks を選んで ノートブックを一つ作ります。 そして、以下のコードをコピペして、オブジェクトストレージの認証情報をご自分の認証情報に変更すれば、準備完了です。認証情報の取得方法は後述します。

次のメソッドで、オブジェクト・ストレージからファイルを取り出して、Python のコードの変数に取り込めます。取り込んだデータは、Num.py の配列に格納すると便利です。 第一引数は認証情報で、コンテナ毎にユーザーIDとパスワードが変えてあるので注意が必要です。 第二引数はオブジェクト（ファイル）名です。コンテナ名は認証情報にセットされいるため、ここで明示的に設定しません。 

~~~py
result,status,Label,Data = Read_CSV_from_ObjectStorage(credentials_1, filename)
~~~

第一戻り値 resultは、成功するとTrue, 失敗すると False が帰ります。
第二戻り値 stautsは、HTTPコードが入っています。 成功の場合は200 がセットされています。 また認証で失敗すると400番台のエラーコードがセットされます。
第三戻り値 Labelは、CSVファイルのヘッダー行にある項目名ラベルのリストが帰ります。
第四戻り値 Dataは、データの内容です。 データは全てFloat型に変換されて配列に入って戻ってきます。

以下が、読み取りコードの全体で、以下のコードをDSXのNotebookにコピペして、必要な箇所を変更して利用します。 CSV形式のファイルの列数には、自動対応する様にプログラムしてあります。

~~~py:python読み込み用コード

%matplotlib inline
from io import BytesIO  
import requests  
import numpy as np
import matplotlib.pyplot as plt
import json

# オブジェクトストレージの認証情報  <-- 後述の認証情報取得方法に習って置き換える
credentials_1 = {
  'auth_url':'https://identity.open.softlayer.com',
  'project':'object_storage_bc6cdc85_586e_4581_8a09_8f01f7bdf3ed',
  'project_id':'2a9de4c1d50944a49f1a46dd53394158',
  'region':'dallas',
  'user_id':'********************************',
  'domain_id':'fb119f3e1bc0469dad2b253b317ec7ea',
  'domain_name':'952993',
  'username':'***********************************************',
  'password':"********************",
  'container':'DefaultProjecttakarajpibmcom',
  'tenantId':'undefined',
  'filename':'testdata_for_dsx.csv'
}

# オブジェクトストレージからの読み込み
def Read_CSV_from_ObjectStorage(credentials, fileName):  
    """This functions returns a StringIO object containing
    the file content from Bluemix Object Storage V3."""

    url1 = ''.join(['https://identity.open.softlayer.com', '/v3/auth/tokens'])
    data = {'auth': {'identity': {'methods': ['password'],
            'password': {'user': {'name': credentials['username'],'domain': {'id': credentials['domain_id']},
            'password': credentials['password']}}}}}
    headers1 = {'Content-Type': 'application/json'}
    resp1 = requests.post(url=url1, data=json.dumps(data), headers=headers1)
    
    # 認証エラーが発生したら終了
    if resp1.status_code != 201:
        return False, resp1.status_code, None, None
    
    resp1_body = resp1.json()
    for e1 in resp1_body['token']['catalog']:
        if(e1['type']=='object-store'):
            for e2 in e1['endpoints']:
                if(e2['interface']=='public'and e2['region']=='dallas'):
                    #url2 = ''.join([e2['url'],'/', credentials['container'], '/', credentials['filename']])
                    url2 = ''.join([e2['url'],'/', credentials['container'], '/', fileName])
    s_subject_token = resp1.headers['x-subject-token']
    headers2 = {'X-Auth-Token': s_subject_token, 'accept': 'text/csv'}
    resp2 = requests.get(url=url2, headers=headers2)
    if resp2.status_code != 200:
        return False, resp2.status_code, None, None
    
    # 配列にセットする
    tempArray = resp2.text.split("\n")  # 行に分割
    csvLabel = []  # CSVの先頭行のラベル
    csvFloat = []  # CSVの２行目以降のデータ部
    lineNo = 0     # 行カウント

    for row in tempArray:
        if len(row) > 0:
            c = row.split(",")
            if lineNo == 0:
                csvLabel = c
            else:
                a = []
                for i in range(0,len(c)):
                    a.append(float(c[i]))
                csvFloat.append(a)                    
        lineNo = lineNo + 1
    return True, resp2.status_code,csvLabel,csvFloat


# サンプル メイン
filename = 'testDataSet.csv'  <-- 読み取りたいCSVファイルのオブジェクト名をセットする

result,status,Label,Data = Read_CSV_from_ObjectStorage(credentials_1, filename)
if result == True:
    a = np.array(Data) # numpy２次元配列 (CSVの列数に依存）

    # グラフ描画
    x = np.array(a[:,[0]]) # 1列目を取り出す
    y = np.array(a[:,[1]]) # 2列目を取り出す
    plt.plot(x,y)
    plt.show()
    
else:    
    print "ERROR ", status
~~~

# オブジェクト・ストレージの認証情報の取得方法

## CSVファイルの登録
最初にDSXのオブジェクトストレージに、CSVファイルを登録しておきます。 ここで、注意点として DSX のプロジェクト と オブジェクト・ストレージのコンテナとが一対一に対応しています。このため Notebookから他のプロジェクトのコンテナにアクセス出来ないので注意が必要です。
このため、自分が現在利用しているプロジェクトに紐付けられたコンテナに、CSVファイルを登録します。メニューバーの Project -> プロジェクト名を指定して、Notebooks, Data Assets　のリスクが表示される画面を開きます。 そして、Data Assets の +Add Data Assets をクリックすると、右端に以下の様な表示がされます。　この Drop file here と表示された破線のエリア内にファイルをドラッグ＆ドロップすると、ファイルがアップロードされます。そして、ファイル名の前のチェックボックスにチェックを入れておきます。 これで Data Assets に表示される様になります。
![スクリーンショット 2017-04-20 13.08.13.png](https://qiita-image-store.s3.amazonaws.com/0/42829/ae8e3f2d-6bef-ae46-5f38-930f6b0fe91c.png)

## 認証情報の取得
次に、Notebookを作成するか、作成途上のNotebookを編集モードで開きます。 編集モードで開くには、ペンのマークのアイコンをクリッックします。そして、![スクリーンショット 2017-04-20 13.13.27.png](https://qiita-image-store.s3.amazonaws.com/0/42829/f3ef9962-63bf-3699-7ca2-cadedc404ac7.png)のアイコンをクリックすることで、次の表示が出ますので、下向き三角をクリックすると、さらにメニューが出てきます。
![スクリーンショット 2017-04-20 13.14.01.png](https://qiita-image-store.s3.amazonaws.com/0/42829/cb684e40-83b2-5311-0a41-4979454e67eb.png)

このリストの中で一番下の Insert Credentials をクリックすることで、Notebookに認証情報が挿入されます。編集して準備完了です。 
![スクリーンショット 2017-04-20 13.14.11.png](https://qiita-image-store.s3.amazonaws.com/0/42829/2cad64ce-1913-2413-7706-d3b5d3d875f7.png)


# コードの実行結果
このコードでは、データを読み込んでグラフを表示する様になっています。CSVファイルのデータに応じたグラフが表示されます。

![スクリーンショット 2017-04-20 13.19.48.png](https://qiita-image-store.s3.amazonaws.com/0/42829/f269a7ab-2e38-6003-92e7-435f731fcc3f.png)





# 参考情報


このコードの元になっている情報は、[Working with Object Storage in Data Science Experience - Python Edition](
https://datascience.ibm.com/blog/working-with-object-storage-in-data-science-experience-python-edition/)の記事のJSON読み込み用コードを元に書き換えた物です。