見出し画像

【初心者向け】図解でわかるNumPyとデータ表現

Jay Alammar氏の記事「A Visual Intro to NumPy and Data Representation」を共訳しました。「実用的な使い方」より前の部分の訳は私が行い、もう片方は上杉周作が行いました。ちなみに原文はCC BY-NC-SAライセンスで公開されているので自由に翻訳できます。この文章も同じくCC BY-NC-SAで公開しています。

NumPyは、Pythonによるデータ分析、機械学習、 科学技術計算において大活躍するパッケージです。NumPyを使うことで、ベクトルや行列の計算がいとも簡単になります。

また、scikit-learn、SciPy、pandas、tensorflowといった人気のパッケージは、NumPyを基にしてつくられています。つまりNumPyをマスターすれば、データの扱いに強くなるだけでなく、NumPyが基になっているパッケージの扱いにも強くなれるのです。

まずは、NumPyの主な使い方と、NumPyを使ってスプレッドシート・画像・テキストといったデータを表す方法を確認しましょう。その後に、そういったデータを機械学習モデルで扱う方法を説明します。

import numpy as np

配列の生成

NumPyで配列(通称「N次元配列」)を生成するにはnp.array()を用い、引数としてリストを渡します。以下の例では、下のような配列が生成されます。

また、新しくNumPyの配列を作る際に、配列の中身をNumPyに指定してもらうこともできます。そういった場合には、ones()zeros()random.random()を使います。引数には、生成したい配列の長さを渡します。

いったん配列を生成してしまえば、それらを様々な方法で応用することができます。

配列の計算

NumPyの利便性がよく分かる例を見てみましょう。ここでは[1, 2][1, 1]の2つの配列を使い、それぞれを「data」「ones」と呼ぶことにします。

同じ行の要素どうしを足し算するには、data + ones とするだけでいいのです。

NumPyのことを知ったときは、「配列同士の計算をする時に、ループを書かなくていいなんて新鮮だ!」と思いました。このような画期的な機能のおかげで、より本質的な問題を解くのに集中できるようになるのです。

足し算だけでなく、引き算、掛け算、割り算も同様の方法で処理することができます。

ベクトルとスカラー間の処理のように、配列と数値の計算を行う場合もあります。例えば、配列内(data)の値が、距離をマイル単位で表しており、それをキロメートルに換算したい場合を考えてみましょう(1マイル = 1.6キロ)。この場合は、data * 1.6 とするだけです。

「配列 * 数字」と表記するだけで、NumPyは「配列のそれぞれの値に数字を掛ければいいんだな」と気を利かせてくれます。これは「ブロードキャスト」と呼ばれる仕組みで、NumPyに備わっている大変便利な機能のひとつです。

インデクシング(インデックスを使った配列操作)

配列のインデックスを指定して部分配列を取り出すことで、配列をいかようにも切り取ることができます。使い方はPythonのリストと同じです。

アグリゲーション(集約)

アグリゲーション機能も便利な機能のひとつです:

minmaxsumに加え、平均を算出するmean 、全ての要素の積を計算するprod 、標準偏差を計算するstd など、その他にも様々な機能が備わっています。

多次元への応用

これまで見てきた例は、すべて1次元の配列(ベクトル)を扱うものでした。NumPyが優れている理由のひとつは、これまで紹介した機能すべてを、多次元の配列(行列)でも同様に使えることです。

行列の生成

NumPyで行列を生成するには、以下のように np.array() を用います。引数には、リストを要素として持つリストを渡します。

np.array([[1,2],[3,4]])

また、先ほど紹介したones()zeros()random.random() を使って行列を作成するには、生成したい行列の型をタプルで指定します。

行列の計算

2つの行列の型が同じ場合、演算記号(+-*/)を用いることで、2つの行列の足し算や掛け算といった計算を行うことができます。この場合NumPyは、同じ位置にある値どうしに対して計算を行います。

ただ、型が異なる2つの行列を扱う場合でも計算を行うことができる場合があります。それは、

・2つの行列の間で行数が異なるが、片方の行数が1の場合
・2つの行列の間で列数が異なるが、片方の列数が1の場合

です。NumPyのブロードキャストの仕組みによって自動で行・列を拡張することにより、何の問題もなく計算できるのです。

行列積

NumPyは、同じ位置にある値の四則演算だけでなく、ベクトルの内積や行列の積の計算もできます。行列積を求めるには、dot() を用います。

上の図のdatapowers_of_tenの行列の下には、それぞれの行列の型を示しています (1×3と3×2)。ひとつめの行列の列の数と、ふたつめの行列の行の数 (図だと赤色の数字) を揃えないと積を求めることができません。

上記の掛け算で行われている処理を図解すると、以下のようになります。

行列のインデクシング

先ほど紹介したインデクシングは、行列を扱う際にさらに役立ちます。

行列のアグリゲーション(集約)

1次元ベクトルと同じように、行列においてもアグリゲーション機能を用いることができます。

axis を用いて軸を指定することで、同じ行、あるいは同じ列にある値に対してアグリゲーションを行うこともできます。例えば、axis=0 と指定すると同じ行にある値を、axis=1 と指定すると同じ列にある値をまとめることができます。

転置と形状変換

行列を扱う上で、行列を回転させて行と列を入れ替える必要が出てくることもあります。例えば、ドット積を求めるために2つの行列間の列数と行数を揃えなければならない場合などです。行列の行と列を置き換え、転置行列を得るには T を用います。

さらに高度なケースでは、ある行列の次元を変換しなければならない場合もあるでしょう。これは機械学習ではよくあるケースで、元となるデータセットとは異なる形でデータを入力しなければならない場合などです。

このようなケースには、NumPyのreshape() 機能が有効です。引数として渡すのは、変換後に得たいデータの行数・列数です。また、行数・列数のどちらかに-1を渡した場合、NumPyはもう片方の値から適切な値を自動で推測し、変換を行ってくれます。

さらに多次元への応用

NumPyは、これまで紹介した全ての機能を、さらなる多次元配列に対しても適用することができます。その核となるデータ構造は「N次元配列」と呼ばれます。

ones() などを使ってN次元配列を生成するには、引数のタプルで生成したい配列の型を指定します。

実用的な使い方

ここからは、上杉周作の訳になります。

それでは、学んだことを活かしてみましょう!NumPyが役に立つ場面をいくつか紹介します。

数式を実装する

行列やベクトルを用いた数式をPythonで実装する際にNumPyはとても役立ちます。これが、科学技術計算でNumPyが重宝される一番の理由です。

例として、Mean Squared Error(平均二乗誤差)の式を見てみましょう。教師あり学習における回帰分析問題を解くのに必要不可欠な式です。

NumPyを使えば、MSEをたやすく実装することができます:

NumPyを使う利点のひとつは、predictionslabelsの中に入っている値がひとつであろうと1000個であろうと関係なく計算できることです。(predictionslabelsの大きさが同じである必要はありますが。)

上のコードを、適当なpredictionslabelsの例を用いてステップごとに追ってみましょう:

predictionslabelsのベクトルには、それぞれ3つの値が入っています。ということは、nに3を代入します。ベクトルの引き算をすると、次のようになります:

続いて、ベクトルの値をすべて二乗します:

最後に、ベクトルの値を合計します:

出てきた値が、モデルの精度を表す平均二乗誤差というわけです。

データ表現

スプレッドシート・画像・音声などのデータを処理したり、それらをもとにモデルを構築する際には、まずはN次元配列でデータを表現することからはじめます。

スプレッドシート(表計算)

スプレッドシートの値は行列(2次元配列)で表現することができます。ひとつのファイルに複数のシートがある場合、それぞれのシートを変数に保存すればいいでしょう。こういったデータを扱う際には、PandasのDataFrameが最もよく使われています。ちなみにPandasはNumPyが基になっています。

音声データと時系列データ

音声データは標本値の1次元配列で表現することができます。それぞれの標本値は、音声信号の小さな一部分を表しています。CD並みの音質の音声データには1秒あたり4万4100の標本値が必要で、それぞれの値は-65535から65536の間になります。

たとえば、CD並みの音質の、長さが10秒のWAVEファイルの場合、長さが10 × 44100 = 44万1000のNumPy配列で表すことができます。これをaudioという変数に入れたとして、最初の1秒だけを取り出したければ、audio[:44100]とすれば良いのです。

音声データの抽出を図で表すと、次のようになります:

他にも、たとえば株価の変動といった時系列データも同じように表現できます。

画像データ

画像データは、ピクセルの行列(縦×横)の集合です。

白黒(グレースケール)画像の場合、それぞれのピクセルを0(黒)から255(白)の数字で表すのが一般的です。左上の10 × 10ピクセルを抽出したい場合は、NumPyでimage[:10, :10]と指定すればOKです。

カラー画像の場合、それぞれのピクセルは赤・緑・青の数値で表されます。この場合、2次元の行列ではデータを表現しきれないので、3次元の配列(縦×横×3)が必要になります。

言語

言語を扱う場合は、これまでとちょっと違います。文章を数字で表すためには、その言語モデルに登場しうるすべての単語をリスト化し、さらに「単語埋め込み」を行う必要があります。

例として、古典「アンタル物語」に登場する以下の一節を数値化してみましょう(訳注: この文章についての詳しい解説は原文を参照のこと):

Have the bards who preceded me left any theme unsung?

言語モデルを作る際にはまず、膨大な量の文章を読み込まなければいけません。というわけで、こちらのデータセットをもとに、7万1290の単語をリスト化しました。

続いて、先ほどの文を単語の配列にします。(それぞれの値を単語ではなく、単語の一部分にするほうが良い場合もあります)

続いて、それぞれの値を単語リストで該当する番号に変えます。

これだけでは、モデルが学習をするための情報が足りません。そのため、まず先に単語を分散表現(単語埋め込み)で表す必要があります。こちらは、50次元のWord2Vecを利用した例です:

この配列の次元は、「分散表現の次元 × 単語の数」になります。(実際は「単語の数 × 分散表現の次元」を使うのですが、図を分かりやすくするためにこうしています。)

深層学習を使う場合、並列処理による高速化を実現するため、ひとつめの次元はバッチサイズを使うことが多いです。この際、reshape()がとても役に立ちます。BERTのようなモデルの場合、入力する配列の次元は「バッチサイズ×単語の数×分散表現の次元」になります。

このように文章を数値化することで、モデルが学習したり予測できるようになります。ちなみに上記の図では他の行が空になっていますが、ここには他の文を表す数値が入ります。

よければシェアしてください😉


42
A jewelry designer & a junior JavaScript/Python developer🐥 Based in CA, USA🇺🇸 My work: http://sayajewels.com 💌: sayazamurai38@gmail.com
コメントを投稿するには、 ログイン または 会員登録 をする必要があります。