【NumPy入門】配列の四則演算と数学関数!要素をまとめて計算する方法

Python

こんにちは、ぼりたそです!

今回は、NumPyの配列を使って、複数の数値をまとめて計算する方法について解説します。

NumPyでは、配列のすべての要素に同じ数値を足したり、2つの配列の対応する要素を掛けたりできます。また、平方根や絶対値なども、配列に対してまとめて計算できます。

データ分析や機械学習では、測定値の補正や単位の変換など、複数の数値に同じ計算を行う場面が多いため、ぜひ覚えておきたいですね。

この記事では、以下のポイントを解説します。

Point
  • 四則演算:配列のすべての要素に同じ計算を行う
  • 配列同士の計算:同じ位置の要素を組み合わせる
  • べき乗・数学関数:2乗、平方根、絶対値、指数・対数を計算する
  • PythonのリストとNumPy配列の計算の違い
  • 元の配列を更新する場合や、計算する値の注意点

それでは順番に確認していきましょう!

スポンサーリンク

NumPyで配列をまとめて計算するには?

NumPyでは、配列に演算子や数学関数を適用すると、各要素に対して計算を行えます。

例えば、配列に2を掛けると、配列の中にあるそれぞれの値が2倍になります。このような計算を「要素ごとの計算」と呼びます。

Pythonのfor文で要素を1つずつ取り出す処理を書かなくても、配列を使った式でまとめて表せることが特徴です。

NumPyを使用するには、最初にライブラリを読み込みます。

import numpy as np

以降のコードは、この読み込みを実行した状態を前提とします。今回は、整数や小数を要素に持つ通常のNumPy配列を使用します。

配列の作成方法については、次の記事も参考にしてみてください。

四則演算:すべての要素に同じ計算を行う

まずは、配列と1つの数値を使った四則演算を確認してみましょう。

ここでは、次の配列aを使用します。

a = np.array([10, 20, 30, 40])

配列に対して計算する10や2のような、単独の数値を「スカラー」と呼びます。

足し算:すべての要素に同じ値を足す

すべての要素に同じ値を足す場合は、+を使います。

print(a + 10)

# 実行結果:
# [20 30 40 50]

10 + 10、20 + 10、30 + 10、40 + 10が、それぞれ計算されています。

例えば、測定値をすべて同じ量だけ補正したいときに使えます。

引き算:すべての要素から同じ値を引く

引き算には、-を使います。

print(a - 10)

# 実行結果:
# [ 0 10 20 30]

この例では、各要素から10を引いています。

なお、引き算では、配列と数値を書く順番によって結果が変わります。

print(100 - a)

# 実行結果:
# [90 80 70 60]

100 - aでは、100から配列の各要素を引いています。

掛け算:すべての要素を同じ倍率にする

掛け算には、*を使います。

print(a * 2)

# 実行結果:
# [20 40 60 80]

配列全体に2を掛けるだけで、各要素を2倍にできます。

例えば、単位を変換したり、すべての値に同じ係数を掛けたりするときに便利です。

割り算:すべての要素を同じ値で割る

割り算には、/を使います。

print(a / 4)

# 実行結果:
# [ 2.5  5.   7.5 10. ]

各要素を4で割った結果が得られます。

整数型の配列でも、/による割り算の結果は浮動小数点数になります。 出力の5.や10.は、それぞれ5.0、10.0を表しています。

ここまでの書き方をまとめると、次のようになります。

書き方計算の内容
a + 10各要素に10を足す
a - 10各要素から10を引く
a * 2各要素を2倍する
a / 4各要素を4で割る

なお、ここまでのprint(a + 10)などの操作では、計算結果を表示しているだけなので、元の配列aの値は変わりません。

配列同士の計算:同じ位置の要素を組み合わせる

次に、2つの配列を使って計算してみましょう。

同じ形状の配列同士では、同じ位置にある要素を組み合わせて計算します。

ここでは、要素数が3の配列を2つ作成します。

a = np.array([10, 20, 30])
b = np.array([1, 2, 3])

print(a + b)
print(a - b)
print(a * b)
print(a / b)

# 実行結果:
# [11 22 33]
# [ 9 18 27]
# [10 40 90]
# [10. 10. 10.]

例えば、a * bでは、次の組み合わせで計算しています。

位置計算結果
先頭10 * 110
2番目20 * 240
3番目30 * 390

配列のすべての値を組み合わせるのではなく、対応する位置同士で計算することがポイントです。

なお、形状が異なる配列同士でも、「ブロードキャスト」という仕組みで計算できる場合があります。配列とスカラーの計算もその一例です。詳しい条件は別の記事で扱いますので、まずは同じ形状の配列同士の計算を押さえておきましょう。

2次元配列でも要素ごとに計算できる

行と列を持つ2次元配列でも、同じように計算できます。

例えば、次の2行3列の配列を2倍してみましょう。

data = np.array([
    [10, 20, 30],
    [40, 50, 60]
])

result = data * 2

print(result)
print(result.shape)

# 実行結果:
# [[ 20  40  60]
#  [ 80 100 120]]
# (2, 3)

行と列の配置を保ったまま、各要素が2倍になっています。shapeは配列の形状を表す属性で、(2, 3)は2行3列という意味です。

同じ形状の2次元配列同士でも、対応する行・列の要素を組み合わせて計算できます。

なお、NumPy配列の*は要素ごとの掛け算です。 数学で扱う行列積とは異なります。行列積には@などを使いますが、今回の記事では要素ごとの計算を扱います。

スポンサーリンク

べき乗:各要素を2乗・3乗する

べき乗には、Pythonの数値計算と同じく**を使います。

例えば、配列の各要素を2乗・3乗してみましょう。

x ** 2では、1 ** 2、2 ** 2、3 ** 2、4 ** 2が、それぞれ計算されています。

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

print(x ** 2)
print(x ** 3)

# 実行結果:
# [ 1  4  9 16]
# [ 1  8 27 64]

ここで注意したいのは、べき乗に使う記号は^ではなく、**であるという点です。Pythonの^は、整数などのビット演算に使う別の演算子です。

数学関数:平方根や絶対値をまとめて計算する

NumPyには、配列の各要素に適用できる数学関数も用意されています。

基本的には、計算したい配列を関数に渡します。

np.sqrt():各要素の平方根を求める

np.sqrt()は、各要素の平方根を求める関数です。実数の範囲では、0以上の値に対して、0以上の平方根を返します。

x = np.array([1, 4, 9, 16])

print(np.sqrt(x))

# 実行結果:
# [1. 2. 3. 4.]

例えば、4の平方根として2.0、9の平方根として3.0が得られています。

np.abs():各要素の絶対値を求める

np.abs()は、各要素の絶対値を求める関数です。実数の絶対値は、数直線上で0からどれだけ離れているかを表します。

x = np.array([-3, -1, 0, 2])

print(np.abs(x))

# 実行結果:
# [3 1 0 2]

負の値は正の値になり、0と正の値はそのままです。

例えば、予測値と実測値の差について、プラス・マイナスの向きではなく、差の大きさを確認したい場合に使えます。

np.exp():各要素に対して指数関数を計算する

np.exp()は、各要素をxとして、eのx乗を計算する関数です。eは約2.71828の定数で、自然対数の底とも呼ばれます。

x = np.array([0, 1, 2])

print(np.exp(x))

# 実行結果:
# [1.         2.71828183 7.3890561 ]

この例では、eの0乗、1乗、2乗を計算しています。

先ほどのx ** 2は「各要素を2乗する」計算ですが、np.exp(x)は「eを各要素の値でべき乗する」計算です。

np.log():各要素の自然対数を求める

np.log()は、各要素の自然対数を求める関数です。

自然対数は、「eを何乗すると、その値になるか」を表します。例えば、eの0乗は1なので、1の自然対数は0です。

x = np.array([1, np.e, np.e ** 2])

print(np.log(x))

# 実行結果:
# [0. 1. 2.]

np.eは、NumPyで定数eを表す書き方です。この例では、1、e、eの2乗の自然対数を、それぞれ求めています。

np.log()が求めるのは、底が10の対数ではなく、底がeの自然対数です。

np.exp()とnp.log()の関係

np.exp()は指数から値を求め、np.log()はその値から指数を求めます。

例えば、np.exp()で計算した結果にnp.log()を適用すると、次のようになります。

x = np.array([0, 1, 2])
y = np.exp(x)

print(np.log(y))

# 実行結果:
# [0. 1. 2.]

数学的には逆の操作ですが、コンピューターの計算では丸め誤差が生じることがあり、常に元の値と完全に一致するとは限りません。

また、極端に大きい値や小さい値では、np.exp()の結果がinfや0になり、元の値に戻せない場合もあります。

PythonのリストとNumPy配列の計算の違い

PythonのリストとNumPy配列では、同じ演算子を使っても、動作が異なる場合があります。

例えば、どちらにも2を掛けてみましょう。

values = [10, 20, 30]
a = np.array(values)

print(values * 2)
print(a * 2)

# 実行結果:
# [10, 20, 30, 10, 20, 30]
# [20 40 60]

リストでは、* 2によって同じ並びを2回繰り返します。一方、NumPy配列では、各要素を2倍します。

+でも、同じように違いがあります。

print([10, 20, 30] + [1, 2, 3])
print(np.array([10, 20, 30]) + np.array([1, 2, 3]))

# 実行結果:
# [10, 20, 30, 1, 2, 3]
# [11 22 33]

リスト同士の+は連結ですが、NumPy配列同士の+は、対応する要素の足し算です。

数値をまとめて計算したい場合は、対象がリストなのかNumPy配列なのかを確認しておきましょう。

配列を使って計算する際の注意点

計算結果を別の配列にする場合と、元の配列を更新する場合

計算前の値を残したい場合は、結果を別の変数に保存できます。

a = np.array([10, 20, 30])
b = a + 10

print(a)
print(b)

# 実行結果:
# [10 20 30]
# [20 30 40]

a + 10の結果を持つ新しい配列が作られるため、元の配列aは変わりません。

一方、+=を使うと、現在の配列の要素を直接更新します。

a = np.array([10, 20, 30])
a += 10

print(a)

# 実行結果:
# [20 30 40]

-=、*=、/=も、現在の配列を更新するための書き方です。

ただし、更新する配列のデータ型によっては、計算結果を格納できずにエラーになります。例えば、整数型の配列にa /= 2とすると、割り算の浮動小数点数の結果を整数型の配列へ書き戻せないため、エラーになります。

その場合は、b = a / 2のように結果を新しい配列として受け取るか、あらかじめ浮動小数点数の配列を用意します。

また、前回の記事で扱ったビューに対して+=などを使うと、データを共有する元の配列にも変更が反映されます。元データを残したい場合は、変更する前にcopy()で独立させましょう。

割り算や数学関数に渡す値に注意する

計算する値によっては、通常の数値として結果を得られない場合があります。

今回のように実数を扱い、NumPyの標準のエラー設定を使う場合、代表的な例は次のとおりです。

計算結果注意点
浮動小数点数の1.0 / 0.0をNumPyで計算inf無限大を表す
浮動小数点数の0.0 / 0.0をNumPyで計算nan通常の数値として結果を表せない
np.sqrt(-1.0)nan実数の範囲では負の値の平方根を求められない
np.log(0.0)-inf0の自然対数は有限の値にならない
np.log(-1.0)nan実数の範囲では負の値の自然対数を求められない

これらの計算では、標準の設定で警告も表示されます。 例えば、NumPy配列の割り算は次のようになります。

x = np.array([1.0, 0.0])

print(x / 0.0)

# 実行結果(警告文は省略):
# [inf nan]

Pythonの数値だけで行う1.0 / 0.0はZeroDivisionErrorになりますが、このNumPy配列の計算では、警告とともにinfやnanが返ります。

警告が出ても処理が続く場合があるため、割る値に0が含まれていないか、平方根や対数を計算できる値になっているかを確認することが大切です。

NumPyを基礎から学びたい方へ

今回は、NumPyの配列を使った四則演算や数学関数について紹介しました。

NumPyをデータ分析や機械学習で活用するためには、今回の計算に加えて、条件に合うデータの抽出や集計、配列の形状の変更なども理解しておくと役立ちます。

そこで、NumPyの基本操作を体系的に学びたい方向けに、Kindle書籍『機械学習・データ分析のためのNumPy入門 ― 配列操作と数値計算の基本をPythonで学ぶ ―』を執筆しました。

本書では、配列の作成やインデックス・スライス、条件抽出、集計、ブロードキャストなどを、コード例と演習問題を通じて学べる構成にしています。

「説明を読むだけでなく、自分でコードを書いて理解を深めたい」「データ分析や機械学習に向けてNumPyの基本を身につけたい」という方は、ぜひチェックしてみてください!

まとめ

今回は、NumPyの配列を使って、複数の数値をまとめて計算する方法について解説しました。

今回紹介した主な書き方をまとめると、次のようになります。

書き方用途・特徴
a + 10、a - 10各要素に同じ値を足す・引く
a * 2、a / 4各要素に同じ値を掛ける・割る
a + b、a * b同じ形状の配列の、対応する要素同士を計算する
a ** 2各要素を2乗する
np.sqrt(a)各要素の平方根を求める
np.abs(a)各要素の絶対値を求める
np.exp(a)各要素を指数として、eのべき乗を計算する
np.log(a)各要素の自然対数を求める
b = a + 10計算結果を新しい配列として保存する
a += 10元の配列の各要素に10を足して更新する

NumPyの基本的な四則演算や、今回紹介した数学関数は、配列の要素ごとに計算することがポイントです。

また、リストとは演算子の動作が異なることや、+=などでは元の配列を更新することにも注意しましょう。

まずは今回紹介したコードを実際に動かして、数値や計算式を変えると、各要素の結果がどのように変わるかを確認してみてください!

スポンサーリンク
タイトルとURLをコピーしました