wastonx.ai Studio上のnotebookからプロジェクトの資産にあるファイルの読み書き - ibm_watson_studio_libを使う -

この記事は2020年03月24日に公開した「[Watson Studio上のnotebookからIBM Cloud Object Storage(ICOS)へのFileの読み書き - project-libを使う -](https://qiita.com/nishikyon/items/1bed62a2a98b0c970f40)」のibm_watson_studio_lib版です。文章も使える部分はそのままにしてます。

5年も経つと製品の名前もライブラリーも変わってしまっていて、最近方法を聞かれたので新しいGUIと新しいライブラリーでの手順を記載します(「新しい」のは2025年1月現在の話ですが)。

ちなみに「Watson Studio」は「wastonx.ai Studio」に名前が2024年11月に変更になりました。

---

Notebookでコードを書く際、データをファイル経由でロードするのはごく頻繁にあるケースです。ローカルのPC上でjupyter Notebookを動かしている場合は、普通のpythonのお作法で読み書きすれば問題ないですのですが、wastonx.ai Studioのプロジェクトのファイル置き場である「資産」にあるファイルをNotebook上で読み書きする場合は、一般的にはプロジェクトに紐ついたIBM Cloud Object Storage(以下ICOS)に対してファイルの読み書きすることになります。

方法はいくつかあります。ICOSはAWS S3互換のオブジェクトストレージなので、AWS S3と同様の方法も使えます。またwastonx.ai StudioのNotebookの空のコード・セルをクリックし、Notebookのツールバーから 「コード・スニペット」 アイコン (「コード・スニペット」アイコン) をクリックし、 「データの取り込み」 とプロジェクトの資産を選択することで、`pandas DataFrames`や`Credentials`を使って[コード生成する方法](https://dataplatform.cloud.ibm.com/docs/content/wsj/analyze-data/data-load-support.html?context=cpdaas&locale=ja&audience=wdp)もあります。あとはwastonx.ai StudioのNotebook専用となりますが、割と簡単に書ける`ibm_watson_studio_lib`を使う方法があります。

ここではこの方法の1つ、`ibm_watson_studio_lib`を使った方法を説明します。

尚ここに書いてある情報はwastonx.ai Studioのドキュメント「[ibm-watson-studio-lib (Python 用)](https://www.ibm.com/docs/ja/watsonx/saas?topic=lib-watson-studio-python)」の情報を元にしています。


# 0. 前提はwastonx.ai Studioのプロジェクトが作成済みであること
前提は既にwastonx.ai Studioのプロジェクトが作成済みであることです。もしまだ作成済みでなく、方法がわからない場合は

* [wastonx.ai Studio サービスとプロジェクトの作成](https://qiita.com/nishikyon/items/55b2b71eed9996f82d42/)

を参考にまずプロジェクトを作成してから以下を開始してください。

# 1. まずはやること
ライブラリーを使う前にやることです！

## 1-1. プロジェクトを開く
作成済みプロジェクトを開いてください。

方法がわからない場合は
「[wastonx.ai Studio サービスとプロジェクトの作成 - 4. プロジェクトの開き方](https://qiita.com/nishikyon/items/55b2b71eed9996f82d42#4-%E3%83%97%E3%83%AD%E3%82%B8%E3%82%A7%E3%82%AF%E3%83%88%E3%81%AE%E9%96%8B%E3%81%8D%E6%96%B9)」を参考にして開いてください。

## 1-2. 前準備「アクセス・トークン」の作成
`ibm_watson_studio_lib`を使うには、関連付けされたICOSを含むプロジェクトの環境にアクセスできる`アクセス・トークン`を最初に作成しておく必要があります。
**これはプロジェクトに対して1つ作成してあればよいです。** ただし権限別に2つ以上作成するのも問題ありません。

#### 1-2-1: 上部メニューから「管理」をクリックし、左側のメニューから「アクセス制御」を選択します・
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/294516/511c39f0-fca0-e5f9-8426-0919a2137cbe.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/294516/83b4c857-2bb7-b17d-a91c-7dc04d242e7d.png)






#### 1-2-2: 「アクセス・トークン」のタブをクリックします。右側に表示された「新規トークン+」をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/294516/a961bb63-f0e0-9ce2-4f54-b3db17027fcb.png)


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/294516/a5a12e65-1de0-59d8-5ec8-048f95a66aa8.png)



#### 1-2-3: 「新規アクセス・トークン」のウィンドウが表示されますので、「名前」と「アクセス・ロール」を設定し、「作成」をクリックします。

- 名前: 適当にわかりやすい名前(半角で)
- アクセス・ロールの選択:　状況に応じて以下を選択します。
    - 読み込みだけの場合は「Viewer」
    - 読み込みおよび書き込みもしたい場合は「Editor」

この記事では読み込みおよび書き込み方法を説明しますので、「エディター」を設定した状態に設定しました。
アクセス・トークンの追加
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/294516/15af747b-5198-dcde-c90d-b7089da59121.png)


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/294516/e106933d-4fea-7350-215d-95dc69681084.png)



「アクセス・トークン」に設定したトークンが表示されているのを確認します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/294516/84040448-f66b-fa9b-9eb8-58ff00c2febc.png)


これで`ibm_watson_studio_lib`を使うNotebook外での準備が完了しました。

## 1-3. Notebookを開く
既にファイルを読み書きしたいNotebookがあればそれを開いてください。
新たに作ってもよいです。作り方が不明の場合は
[watsonx ai Studio notebookの作成・操作](https://qiita.com/nishikyon/items/05e1f2d4c77a6cab9728/)を参照して作成してください。

## 1-4. 読み込ませたいファイルをプロジェクトの「資産」にアップロード
まずは何かしら 読み込ませたいファイルがある場合は、ICOSにまずファイルをアップロードします。書き込むだけなら不要です。

既にアップロード済みの または　読み込みはしない場合は1-5に進んでください。

#### 1-4-1: 右上の[0100]アイコン(プロジェクトへの資産のアップロード)アイコンをクリックします。

尚、Notebookは編集モードでないとこのアイコンはクリックできません。もし編集モードになっていない場合は、「えんびつ」アイコンがあると思いますので、そちらをクリックして編集モードにしてください。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/294516/b9661ef7-defa-071c-7d59-d8fe47ace84b.png)



#### 1-4-2: 表示された「ここにデータ・ファイルをドロップするか、アップロードするファイルを参照します」が書いてある四角いエリアに、アップロードしたいファイルをドラッグ&ドロップします
あるいは「ここにデータ・ファイルをドロップするか、アップロードするファイルを参照します」をクリックするとファイルダイアログが表示されますので、そこから選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/294516/e6fdd4e7-1c54-2bb1-952f-f272fe3731ff.png)



しばらくするとファイルがロードされ、ロードしたファイル名と「アップロードされました！」というメッセージが表示されます。このファイル名とメッセージがしばらくすると消えてしまいます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/294516/b86348ac-cbe1-51b7-e5f0-0999535bde1e.png)



## 1-5: プロジェクト・トークンのnotebookへの挿入

#### 1-5-1: 空のセルを選択します
空のセルがない場合は、作成して選択してください。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/294516/418f0e48-936d-7d80-da5c-34d7269cff63.png)


#### 1-5-2: 上部メニューの縦の・・・をクリックし、「プロジェクト・トークンの挿入」をクリックします。

[2. 前準備「アクセス・トークン」の作成](#1-2-前準備アクセストークンの作成)でアクセス・トークンを作成してないと、このメニューは表示されないので、もし表示されてない場合は、[2. 前準備「アクセス・トークン」の作成](#1-2-前準備アクセストークンの作成)を実施しているか確認してください。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/294516/982488a8-7e88-f8a6-1dd7-13b92e86454f.png)




**選択していた空のセル**にhidden_cellとして`ws-lib`を使うためのライブラリを読み込み、設定したtokenを使用した必要なコードが書かれたコード挿入されます。

尚、以前の`project-lib`を使うためのコードも上部に挿入されるのですが、こちらは使いません。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/294516/57368789-adff-fa85-58d8-7f86cd23abc1.png)



#### 1-5-3: セルをクリックして以下のいずれかの方法で実行をします。

- [Shift] + [Enter] を入力
- Windows： Ctrl + Enter
- Mac: ⌘ (command) + Enter 　または Ctrl + Enter
- 上のメニューから`▶︎` ボタンをクリック
  

実行が完了すると以下の部分に数字が入ります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/294516/280f0073-11ce-24ff-14f9-4ddec763252d.png)


これでnotebookの準備は完了です。この作業はnotebook毎に１回必要です。

# 2. ibm_watson_studio_libを使ってファイルの読み書き
もろもろの準備ができたので`ibm_watson_studio_lib`を使ってみましょう!

では早速notebook上でProjectの資産のファイルを読み書きしてみましょう。1-5で挿入されたセルは実行済みの前提です。

## 2-1: Projectの資産 <-> notebook ランタイムのファイル・システム間のファイルのコピー
よく本などに載っているサンプルコードでファイルを扱うものは、localのストレージ直で読み書きするものです。notebookの場合、notebookを編集状態にするたびにランタイムが立ち上がりますので、そのファイル・システム領域にファイルをコピーしておけば、localのストレージにあるのと同じですので、サンプルコードはそのまま使えます。逆にサンプルコードで保存した場合は、ランタイムのファイル・システム領域にコピーされてますので、notebookを閉じる前に、 Projectの資産にコピーしておけば、notebookを閉じてもファイルは保存され、ダウンロードも可能です。

### 2-1-1:  プロジェクトの資産からランタイムのファイル・システムへのコピー
[データの取り出し](https://www.ibm.com/docs/ja/watsonx/saas?topic=lib-watson-studio-python#fetch-data) より抜粋

- **download_file(asset_name_or_item, file_name=None, attachment_type_or_item=None)**
   - このファイルが既に存在している場合は、上書きされます。

  - `asset_name_or_item`: (必須) 保管されているデータ資産の名前

  - `file_name`: (オプション) ダウンロードされたデータが保管されるファイルの名前。 デフォルトでは、資産のファイル名になります。

  - `attachment_type_or_item`: (オプション) ダウンロードするファイルのタイプ。  このパラメーターを指定しない場合、デフォルトの添付ファイル・タイプ ( data_asset ) がダウンロードされます。 添付ファイル・タイプが data_assetでない場合は、このパラメーターを指定します。 例えば、プレーン・テキスト・データ資産に自然言語分析のプロファイルが添付されている場合、これは添付ファイル・タイプ data_profile_nluとしてダウンロードできます。

コードの例:
資産にある「地方自治体コード.csv」をコピーします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/294516/518c5c21-1046-0970-d4e2-1e97955ad0e0.png)

```py
filename="地方自治体コード.csv"
wslib.download_file(filename)
```
上記を実行した時の出力:
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/294516/249ddcaf-3e53-bafc-d93b-6a1efdd1abcc.png)


コピーができたかどうかは以下のコマンドをセルで実行すれば確認できます。`!`を先頭につけるとランタイムのOSコマンド(Linuxコマンド)が実行できます。

```py
!ls -l
```
実行例:
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/294516/fb7d6e9f-76a7-ad3d-0e9f-fe7f450667b4.png)




###  2-1-2:  ランタイムのファイル・システムからプロジェクトの資産へのコピー
[データの取り出し](https://www.ibm.com/docs/ja/watsonx/saas?topic=lib-watson-studio-python#fetch-data) より抜粋

- **upload_file(file_path, asset_name=None, file_name=None, overwrite=False, mime_type=None)**
    - この関数は、ランタイムのファイル・システム内のデータを、プロジェクトに関連付けられたファイルに保存します。 
    - `file_path`: (必須) ファイル・システム内のファイルへのパス。

    - `asset_name`: (オプション) 作成されるデータ・アセットの名前。 デフォルトでは、アップロードするファイルの名前になります。
    - 
:::note info
このファイル名`asset_name`はなぜか英数字と半角スペース、アンダースコア、ピリオドのみしか使用できません。オリジナルファイル名に日本語や半角スペース、アンダースコア、ピリオド以外の記号が含まれている場合は、このパラメーターで別のファイル名を指定してください。
:::


- <br>

    - `file_name`: (オプション) プロジェクトに関連付けられたストレージ内に作成されるファイルの名前。 デフォルトでは、アップロードするファイルの名前になります。
        - 「デフォルトでは、アップロードするファイルの名前」で、ここも`asset_name`と同じValidationが走るので、オリジナルファイル名に日本語や半角スペース、アンダースコア、ピリオド以外の記号が含まれている場合は、このパラメーターで別のファイル名(asset_nameと同じでよい)を指定してください。
    - 

    - `overwrite`: (オプション) ストレージ内の既存のファイルを上書きします。 デフォルトは false です。

    - `mime_type`: (オプション) 作成されたアセットの MIME タイプ。 デフォルトでは、MIME タイプはアセット名の接尾部から決定されます。 接尾部なしで資産名を使用する場合は、ここで MIME タイプを指定します。 例えば、プレーン・テキスト・データの場合は mime_type='application/text' です。 アセットを上書きする場合、このパラメーターは無視されます。

では上記でランタイムのファイル・システム上にコピーしたファイルをプロジェクトの資産にコピーしてみます。
コピーするファイル名にはライブラリーibm_watson_studio_libの制限で日本語はNGなので`copy_citycode.csv`としています。

ランタイムのファイル・システムにファイルがあるのを念の為確認:
```py
!ls -l
```
実行例:
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/294516/77ec22bd-f5c7-d034-8181-384b33bc4aae.png)

ファイルが動作ディレクトリにあるのが確認できます。


では、このファイル`地方自治体コード.csv`をプロジェクトの資産`copy_citycode.csv`としてコピーしてみましょう。

もし、**既存で同じ名前のファイルを上書きしていい場合は`overwrite=True`のパラメーターも追加しておきます**。


```py
src_filename="地方自治体コード.csv"
target_filename="copy_citycode.csv"

wslib.upload_file(src_filename,asset_name=target_filename, file_name=target_filename)

# 既存で同じ名前のファイルを上書してもよい場合 overwrite=True を追加
# wslib.upload_file(src_filename,asset_name=target_filename, file_name=target_filename, overwrite=True)
```

ちなみに元ファイル名が「英数字と半角スペース、アンダースコア、ピリオドのみ」で、資産に同じファイル名がなければ、パラメーターはオリジナルファイル名のみを指定すればOKです。
```py
# 元ファイル名が「英数字と半角スペース、アンダースコア、ピリオドのみ」で、
# 資産に同じファイル名がない場合の例
src_filename="filename.csv"
wslib.upload_file(src_filename)
```


確認はプロジェクトの「資産」タブで行います。
「1.保存」して「２.Project名を右クリック」し、「新しいタブで開く」(ブラウザーによって多少表現に違いがあります)をクリックし、別タブでプロジェクトの画面を開きます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/294516/2b76c5a3-92b7-0159-6d8d-047dbd1693e3.png)
↓
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/294516/11af392f-2469-de01-db01-e3ec97840941.png)


資産タブの`全ての資産`にコピーしたファイルが表示されているはずです:
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/294516/9e5bbaf8-4b32-5e05-67b1-5f79f2d11bee.png)

## 2-2:　ランタイムのファイル・システム上のファイルを経由せず資産を直接読み書きする方法
サンプルをそのまま使うとかでなければ、わざわざランタイムのファイル・システム上のファイルを経由しなくてもメモリ上で直接処理が可能です。

### 2-2-1: pandasのDataFrameにプロジェクトの資産から読み込む
[データの取り出し](https://www.ibm.com/docs/ja/watsonx/saas?topic=lib-watson-studio-python#fetch-data) より抜粋

- **load_data(asset_name_or_item, attachment_type_or_item=None)**

    - この関数は、保管されたデータ資産のデータを BytesIO バッファーにロードします。 この機能は、非常に大きなファイルの場合は推奨されません。

    -
    - `asset_name_or_item`: (必須) 保管されているデータ資産の名前を含むストリング、または list_stored_data()によって返されるような項目。

    - `attachment_type_or_item`: (オプション) ロードする添付ファイルのタイプ。 データ資産には、データを含む複数の添付ファイルを含めることができます。 このパラメーターを指定しない場合、デフォルトの接続タイプ、つまり data_asset がロードされます。 添付ファイル・タイプが data_assetでない場合は、このパラメーターを指定します。 例えば、プレーン・テキスト・データ資産に自然言語分析からのプロファイルが添付されている場合、これは添付ファイル・タイプ data_profile_nluとしてロードできます。



では、プロジェクトの資産にある`地方自治体コード.csv`をpandasのDataFrameとして読み込んでみます。

```py
src_filename="地方自治体コード.csv"
my_file = wslib.load_data(src_filename)
my_file.seek(0)

import pandas as pd
df =pd.read_csv(my_file)
df
```
実行例:
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/294516/2255f974-17ba-7d9c-4530-21a49ade8735.png)


### 2-2-2: pandasのDataFrameから資産へCSV形式で保存
[データの保存](https://www.ibm.com/docs/ja/watsonx/saas?topic=lib-watson-studio-python#save-data)　から抜粋

- **save_data(asset_name_or_item, data, overwrite=None, mime_type=None, file_name=None)**

    - この関数は、メモリー内のデータをプロジェクト・ストレージに保存します。
    - `asset_name_or_item`: (必須) list_stored_data()によって返される作成済みの資産またはリスト項目の名前。 既存のファイルを上書きする場合は、この項目を使用できます。
        -  資産に表示される名前です


:::note info
このファイル名`asset_name_or_item`はなぜか英数字と半角スペース、アンダースコア、ピリオドのみしか使用できません。日本語不可です。
:::
   <br> 
   
-
    - `data`: (必須) アップロードするデータ。 これは、タイプ bytes-like-objectの任意のオブジェクト (例えば、バイト・バッファー) にすることができます。

    - `overwrite`: (オプション) 保管データ資産のデータが既に存在する場合は、そのデータを上書きします。 デフォルトでは、これは false に設定されています。 名前の代わりにアセット・アイテムが渡された場合の動作は、アセットを上書きすることです。

    - `mime_type`: (オプション) 作成されたアセットの MIME タイプ。 デフォルトでは、MIME タイプはアセット名の接尾部から決定されます。 接尾部なしで資産名を使用する場合は、ここで MIME タイプを指定します。 例えば、プレーン・テキスト・データの場合は mime_type=application/text です。 アセットを上書きする場合、このパラメーターは無視されます。

    - `file_name`: (オプション) プロジェクト・ストレージで使用されるファイル名。 データは、プロジェクトに関連付けられたストレージに保存されます。 新規アセットの作成時に、ファイル名はアセット名から派生しますが、異なる場合があります。 ファイルに直接アクセスする場合は、ファイル名を指定できます。 アセットを上書きする場合、このパラメーターは無視されます。
    - 


2-2-1で読み込んだDataFrame, dfをcopy_citycode2.csvという名前でプロジェクトの資産に保存します。

```py
target_filename="copy_citycode2.csv"
wslib.save_data(target_filename, df.to_csv(index=False).encode())

# 既存の同じ名前のファイルを上書してもよい場合　overwrite=True を追加
# wslib.save_data(target_filename, df.to_csv(index=False).encode(),overwrite=True)
```

確認方法は[ランタイムのファイル・システムからプロジェクトの資産へのコピー](#2-1-2--ランタイムのファイルシステムからプロジェクトの資産へのコピー)と同じです。

### 2-2-3: プロジェクト資産にあるテキストファイルのStringへの読み込み
直接メモリ上のString の変数にテキストファイルを読み込んでみましょう。
2-2-1で使用した**load_data**を使います。

では、プロジェクトの資産にある`地方自治体コード.csv`をStringの配列に一行つづして読み込んでみます。
```py: 文字コードがUTF-8の場合
from io import TextIOWrapper
src_filename="地方自治体コード.csv"
my_file = TextIOWrapper(wslib.load_data(src_filename), encoding='UTF-8')
my_file.seek(0)
str_liens=my_file.readlines()
str_liens[0:10]
```
実行例:
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/294516/d9fb2515-1d24-aee2-a280-07dda0f58dd4.png)

文字コードがShift-JISの場合はencodingに'sjis'を指定します：
```py: 文字コードがShift-JISの場合
from io import TextIOWrapper
src_filename="202311_02_02202060_SJIS.csv"
my_file = TextIOWrapper(wslib.load_data(src_filename), encoding='sjis')
my_file.seek(0)
str_liens=my_file.readlines()
str_liens[0:10]
```

実行例:
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/294516/253c6d17-de8c-faf6-0615-cae5e50a8ba7.png)



### 2-2-4: String変数からプロジェクト資産にテキストファイルとして書き込む
直接メモリ上のString の変数からプロジェクト資産にテキストファイルとして書き込んでみましょう。
2-2-2で使用した**save_data**を使います。

では、2-2-4で読むこませたStringの配列をプロジェクト資産に`string_city_code.txt`として書き込んでみましょう。
```py
target_filename='string_city_code.txt'
wslib.save_data(target_filename, "".join(str_liens).encode())
```
確認方法は[ランタイムのファイル・システムからプロジェクトの資産へのコピー](#2-1-2--ランタイムのファイルシステムからプロジェクトの資産へのコピー)と同じです。



### 2-2-5: プロジェクト資産にある画像ファイルの表示
`sushi.jpg`という画像ファイルがプロジェクトの資産にアップロードされているとします。以下のコードでnotebook上に表示できます。

```py
src_filename="sushi.jpg"
image_file = wslib.load_data(src_filename)
image_file.seek(0)

from IPython.display import Image
# そのまま表示させると大きすぎるので、幅をwidthで指定
Image(data=image_file.read(), width=500)
# そのまま表示の場合はwidth不要です
# Image(data=image_file.read())
```
実行例:
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/294516/e097c294-3232-7805-1bce-0ce99799d513.png)


以上です。

# 7. まとめ
いかがでしたか? 最初に設定が必要ですが、一度設定すれば以外に簡単にコードが書けたと思います。 
wastonx.ai Studioのドキュメント「[ibm-watson-studio-lib (Python 用)](https://www.ibm.com/docs/ja/watsonx/saas?topic=lib-watson-studio-python)」には他にも資産情報の一覧を出したり、いろいろな使い方が載っていますので、これを参考に他にもいろいろお試しいただければと思います。