Pythonモジュール「NumPy」で配列を操作(代入・参照・コピー・結合・分割など)する方法についてまとめました。
【参照・アクセス・代入】1次元配列、2次元配列
NumPy配列では、リスト型と同じように要素の値に参照・アクセス・代入できます。
書式
| – | 説明 |
|---|---|
| x[i] | 1次元配列xにおけるi番目の要素を参照します。(先頭は0番目) |
| x[i:j] | 1次元配列xにおけるi番目からj-1番目までの要素を参照します。 |
| x[i]=value | 1次元配列xにおけるi番目の要素に値を代入します。 |
| x[i:j]=value | 1次元配列xにおけるi番目からj-1番目までの要素に値を代入します。 |
# -*- coding: utf-8 -*- import numpy as np # 配列の宣言・初期化 x = np.array([1, 2, 3, 4, 5]) # 参照 print(x[4]) # 5 print(x[1:3]) # [2 3] # アクセス・代入 x[4] = 10 x[1:3] = 20 # 代入結果 print(x) # [ 1 20 20 4 10]
NumPyの2次元配列では、リスト型と同じように要素の値をスライスできます。
書式
| – | 説明 |
|---|---|
| x = A[j][i] | 2次元配列Xにおけるj番目の行、i番目の列にある要素を参照します。 |
| x = A[j, i] | 2次元配列Xにおけるj番目の行、i番目の列にある要素を参照します。 |
| x = A[j+h, i+w] | 2次元配列Xにおけるj~j+h番目の行、i~i+w番目の列にある要素を参照します。 |
| A[j][i] = value | 2次元配列Xにおけるj番目の行、i番目の列にある要素に値を代入します。 |
| A[j, i] = value | 2次元配列Xにおけるj番目の行、i番目の列にある要素に値を代入します。 |
| A[j+h, i+w] = value | 2次元配列Xにおけるj~j+h番目の行、i~i+w番目の列にある要素に値を代入します。 |
# -*- coding: utf-8 -*-
import numpy as np
# 配列の宣言・初期化
X = np.array([[1, 2, 3],
[4, 5, 6]])
# 参照
print(X[0][1]) # 2 (0行目1列目の要素)
print(X[0,1]) # 2 (0行目1列目の要素)
print(X[0:2, 0:2]) # [[1 2] (0~1行目,0~1列目の要素)
# [4 5]]
# 代入
X[0:2, 0:2] = 10
print(X) # [[10 10 3]
# [10 10 6]]
| – | 関連記事 |
|---|---|
| 1 | ■【NumPy】1次元配列の先頭・末尾要素に参照・アクセス・代入 |
| 2 | ■【NumPy】2次元配列の要素を参照・スライス・代入 |
【配列のコピー】ndarray.copy
Pythonの数値計算モジュールNumPyでは、ndarray.copyで配列をコピーできます。
この場合、一方のオブジェクトの変更が他方に反映されません。
(「=」を使ってコピーすると一方の変更が他方にも反映されます)
# -*- coding: utf-8 -*-
import numpy as np
x = np.array([1, 2, 3])
# 配列xのコピー
y = x.copy()
y = y * 2
print("x=", x) # x=[1, 2, 3]
print("y=", y) # y=[2, 4, 6]
| – | 関連記事 |
|---|---|
| 1 | ■【NumPy】配列のコピー (ndarray.copy) |
【縦方向に結合】numpy.vstack
Pythonの数値計算モジュール「NumPy」では、numpy.vstackメソッドで配列を縦方向に結合できます。
# -*- coding: utf-8 -*- import numpy as np # 配列の宣言・初期化 A = np.array([[1, 2]]) B = np.array([[3, 4], [5, 6]]) C = np.vstack([A, B]) # 画面出力 print(C) """ [[1 2] [3 4] [5 6]] """
| – | 関連記事 |
|---|---|
| 1 | ■【NumPy】配列を縦方向に結合 (numpy.vstack) |
【横方向に結合】numpy.hstack
numpy.hstackメソッドで配列を横方向に結合できます。
# -*- coding: utf-8 -*- import numpy as np # 配列の宣言・初期化 A = np.array([[1, 2],[3, 4]]) B = np.array([[5, 6], [7, 8]]) C = np.hstack([A, B]) # 画面出力 print(C) """ [[1 2 5 6] [3 4 7 8]] """
| – | 関連記事 |
|---|---|
| 1 | ■【NumPy】配列を横方向に結合 (numpy.hstack) |
【配列の分割】縦方向、横方向
NumPy配列では配列の要素を配列を分割する機能が用意されています。
| – | 説明 |
|---|---|
| y = numpy.vsplit(x, n) | 配列xを縦方向にn個に分割します。 |
| y = numpy.hsplit(x, n) | 配列xを横方向にn個に分割します。 |
# -*- coding: utf-8 -*-
import numpy as np
# 配列の宣言・初期化
x = np.array([[1, 2, 3],
[4, 5, 6]])
# 縦方向に分割
print(np.vsplit(x,2)) # [array([[1, 2, 3]]), array([[4, 5, 6]])]
# 横方向に分割
print(np.hsplit(x,3)) # [array([[1], [4]]),
# array([[2],[5]]),
# array([[3], [6]])]
| – | 関連記事 |
|---|---|
| 1 | ■【NumPy】配列の分割(縦方向・横方向) |
【配列の次元数を変更】numpy.reshape
Pythonの数値計算モジュールNumPyでは、numpy.reshape(m, n)メソッドでm×n(行数m、列数n)の配列に変換できます。
# -*- coding: utf-8 -*- import numpy as np # 1次元配列の宣言・初期化 x = np.array([1, 2, 3, 4, 5, 6]) # 配列の次元を変更(行数2, 列数3の2次元配列に変換) X = x.reshape(2, 3) # 画面出力 print(X) """ [[1 2 3] [4 5 6]] """
1次元配列を2×3の2次元配列に変換できました。
| – | 関連記事 |
|---|---|
| 1 | ■【NumPy】配列の次元数を変更(numpy.reshape) |
【データ型を変更】numpy.astype
Pythonの数値計算モジュールNumPyでは、numpy.astypeで配列要素のデータ型を変更できます。
【詳細】
・データ型の種類一覧
# -*- coding: utf-8 -*-
import numpy as np
# 配列の宣言・初期化
A = np.array([[1, 2],[3, 4]])
# データ型の変換
B = A.astype('float64')
# 画面出力
print(B.dtype) #float64
| – | 関連記事 |
|---|---|
| 1 | ■【NumPy】配列要素のデータ型を変更 (numpy.astype) |
配列の書き込み禁止
配列にread only属性を与えることで、読み込み専用(書き込み禁止モード)に変更できます。
書式
a.flags.writeable = False
※Trueにすると書き込み許可(デフォルト)
# -*- coding: utf-8
import numpy as np
# 配列生成
A = np.array([[1, 0],
[0, 1]])
A.flags.writeable = False
A[0, 0] = 5
# 結果表示
print(A)
上記のプログラムを実行すると、書き込み禁止モード中に書き込みしようとするので
ValueError: assignment destination is read-only
というエラーが出ます。
| – | 関連記事 |
|---|---|
| 1 | ■【NumPy】配列の書き込み禁止 |
【昇順・降順ソート】numpy.sort
NumPy配列では配列の要素を昇順・降順ソートできる機能が用意されています。
書式
| – | 説明 |
|---|---|
| y = numpy.sort(x) | 配列xの要素を昇順ソートします。 |
| y = numpy.sort(x)[::-1] | 配列xの要素を降順ソートします。 |
# -*- coding: utf-8 -*- import numpy as np # 配列の宣言・初期化 x = np.array([1, 3, 2]) print(np.sort(x)) # 昇順 [1 2 3] print(np.sort(x)[::-1]) # 降順 [3 2 3]
| – | 関連記事 |
|---|---|
| 1 | ■【NumPy】配列のソート(昇順・降順) |
【要素の位置をずらす】numpy.roll
NumPyには、numpy.roll(ndarray, num)メソッドで配列ndarrayの要素をnum個分だけ左右にずらします。
# -*- coding: utf-8 -*-
import numpy as np
# 1次元配列の生成
x = np.array([1, 2, 3, 4, 5])
# 右に1要素分ずらす
x1 = np.roll(x, 1)
print('x1=', x1) # x1= [5 1 2 3 4]
# 左に1要素分ずらす
x2 = np.roll(x, -1)
print('x2=', x2) # x2= [2 3 4 5 1]
| – | 関連記事 |
|---|---|
| 1 | ■【NumPy】配列の要素の位置をずらす |
【算術演算】配列の要素同士を計算
算術演算子(*, /, +, -)で配列の要素同士の掛け算、割り算、足し算、引き算ができます。
掛け算
# -*- coding: utf-8 -*- import numpy as np # 配列の宣言・初期化 A = np.array([[1, 2],[3, 4]]) B = np.array([[5, 6], [7, 8]]) C = A * B # 画面出力 print(C) """ [[ 5 12] [21 32]] """
割り算
# -*- coding: utf-8 -*- import numpy as np # 配列の宣言・初期化 A = np.array([[1, 2],[3, 4]]) B = np.array([[5, 6], [7, 8]]) C = B / A # 画面出力 print(C) """ [[5 3] [2 2]] """
余り
# -*- coding: utf-8 -*- import numpy as np # 配列の宣言・初期化 A = np.array([[1, 2],[3, 4]]) B = np.array([[5, 6], [7, 8]]) C = B % A # 画面出力 print(C) """ [[0 0] [1 0]] """
累乗
# -*- coding: utf-8 -*- import numpy as np # 配列の宣言・初期化 A = np.array([[1, 2],[3, 4]]) B = A**2 # 画面出力 print(B) """ [[ 1 4] [ 9 16]] """
| – | 関連記事 |
|---|---|
| 1 | ■【NumPy】配列の要素同士の掛け算 |
| 2 | ■【NumPy】配列の要素同士の割り算 |
| 3 | ■【NumPy】配列の要素同士の余り |
| 4 | ■【NumPy】配列の要素の累乗 |
【データ抽出】行・列、要素、インデックス<
2次元配列から特定の行にある配列(1次元配列)を取り出せます。
書式
ndarray[要素番号]
■返り値
(要素番号+1)行目のデータ(1次元配列)
例えばndarray[1]なら2行目のデータを取り出せます。
# -*- coding: utf-8
import numpy as np
# 2次元配列
A = np.array([[1, 2],
[3, 4],
[5, 6]])
# 1行目の値を取り出し
a1 = A[0]
# 結果表示
print(a1) # [1 2]
| – | 関連記事 |
|---|---|
| 1 | ■【NumPy】2次元配列から特定の行を取り出し |
Pythonの数値計算モジュールNumPyでは、次のようにして2次元配列から特定の列にあるデータを取り出せます。
書式
ndarray[ : , 要素番号]
■返り値
(要素番号+1)列目のデータ(1次元配列)
例えばndarray[1]なら2列目のデータを取り出せます。
# -*- coding: utf-8
import numpy as np
# 2次元配列
A = np.array([[1, 2],
[3, 4],
[5, 6]])
# 1列目の値を取り出し
a1 = A[:,1]
# 結果表示
print(a1) # [2 4 6]
| – | 関連記事 |
|---|---|
| 1 | ■【NumPy】2次元配列から特定の列を取り出し |
NumPyの「numpy.where」を利用することで、指定した条件を満たす配列(リスト)の要素番号を取り出すことが出来ます。
書式
np.where(条件式)
今回は、配列y内の数値データのうち、10以上20未満のデータがある要素を取り出す。
# -*- coding: utf-8 -*- import numpy as np # 配列の宣言 y = np.array([8,9,10,11,15,18,22,21,20,29]) # 条件式(10以上20未満)を満たす要素を抽出 y2 = y[ np.where( (y>=10) & (y<20)) ] # 結果を表示 print(y2) #
| – | 関連記事 |
|---|---|
| 1 | ■【NumPy】配列から条件を満たす要素を抽出 |
NumPy配列では、numpy.random.choiceで配列から要素をランダム抽出できます。
書式
b = numpy.random.choice(a, n, replace=True)
配列aから要素n個をランダムに抽出します。
(replaceがTrueなら重複あり)
b = numpy.random.choice(a, n, p= [0.1, 0.9])
各要素の出現確率pを指定して配列aから要素n個をランダムに抽出します。
# -*- coding: utf-8 import numpy as np # 配列生成 a = np.array([1, 2, 3]) # 配列のランダム抽出 c1 = np.random.choice(a, 3, replace=True) # 重複あり c2 = np.random.choice(a, 3, replace=False) # 重複なし c3 = np.random.choice(a, 3, p=[0.1, 0.8, 0.1]) # 出現率pを指定 # 結果表示 print(c1) # [2 3 2] print(c2) # [1 2 3] print(c3) # [2 2 2]
| – | 関連記事 |
|---|---|
| 1 | ■【NumPy】配列から要素のランダム抽出 |
NumPyの「numpy.where」を利用することで、指定した条件を満たす配列(リスト)の要素番号を取り出すことが出来ます。
書式
np.where(条件式)
今回は、配列y内の数値データのうち、10以上20未満のデータがある要素番号xを取り出す。
# -*- coding: utf-8 -*- import numpy as np # 配列の宣言 y = np.array([8,9,10,11,15,18,22,21,20,29]) # 条件を満たすインデックスを取得 x = np.where((y>=10)&(y<20)) # [2 3 4 5] # 結果を表示 print(x[0])
| – | 関連記事 |
|---|---|
| 1 | ■【NumPy】配列から条件を満たす要素番号を抽出 |
NumPyでは、配列の非0要素のインデックス(要素番号・位置)を取り出す機能が用意されています。
書式
| – | 説明 |
|---|---|
| index = numpy.nonzero(x) | 配列xの値が0以外の要素のインデックスを取得します。 |
# -*- coding: utf-8 -*- import numpy as np # 配列の宣言 x = np.array([2, 1, 0]) # 非0要素のインデックス print(np.nonzero(x)) # (array([0, 1]),)
| – | 関連記事 |
|---|---|
| 1 | ■【NumPy】非0要素のインデックス |
NumPyでは、配列の最大値・最小値要素のインデックス(要素番号・位置)を取り出す機能が用意されています。
書式
| – | 説明 |
|---|---|
| index = numpy.argmin(x) | 配列xの最小値要素のインデックスを取得します。 |
| index = numpy.argmax(x) | 配列xの最大値要素のインデックスを取得します。 |
# -*- coding: utf-8 -*- import numpy as np # 配列の宣言 x = np.array([2, 1, 3]) # 最小値要素のインデックス print(np.argmin(x)) # 1 # 最大値要素のインデックス print(np.argmax(x)) # 2
| – | 関連記事 |
|---|---|
| 1 | ■【NumPy】最大値・最小値要素のインデックス |
【情報取得】配列サイズ、要素数、データ型、次元数、バイト数
numpy.shapeメソッドで配列の大きさ(行数・列数)を取得できます。
# -*- coding: utf-8 -*-
import numpy as np
# 2次元配列の宣言・初期化
A = np.array([[1, 2],
[3, 4],
[5, 6]])
# 行列の大きさ
print("行列Aの大きさ:", A.shape)
print("行列Aの行数:", A.shape[0])
print("行列Aの列数:", A.shape[1])
"""
行列Aの大きさ:(3, 2)
行列Aの行数:3
行列Aの列数:2
"""
| – | 関連記事 |
|---|---|
| 1 | ■【NumPy】配列の大きさ(行数・列数)を取得 |
numpy.dtypeで配列要素のデータ型を表示できます。
# -*- coding: utf-8 -*- import numpy as np # 配列の宣言・初期化 A = np.array([[1, 2],[3, 4]]) # 画面出力 print(A.dtype) # int32
| – | 関連記事 |
|---|---|
| 1 | ■【NumPy】配列要素のデータ型を表示 (numpy.dtype) |
numpy.diag(array)メソッドで配列arrayの対角成分を取り出すことができます。
# -*- coding: utf-8 -*-
import numpy as np
# 配列の宣言・初期化
A = np.array([[1, 2, 3],
[4, 5, 6],
[7, 8, 9]])
# 画面出力
print(np.diag(A)) # [1 5 9]
| – | 関連記事 |
|---|---|
| 1 | ■【NumPy】行列(配列)の対角成分を取得 (numpy.diag) |
count_nonzeroメソッドで、値が0でない要素数をカウントできます。
今回はそれを用いて0の要素数を求めてみました。
書式
numpy.count_nonzero(ndarray)
■返り値
値が0でない要素数
# -*- coding: utf-8 import numpy as np # 配列生成 A = np.array([0, 1, 1, 1, 2, 0, 0]) # 0の要素数 = 全要素数 - 0でない要素数 num = len(A) - np.count_nonzero(A) # 結果表示 print(num) # 3
| – | 関連記事 |
|---|---|
| 1 | ■【NumPy】値が0である要素数をカウント |
count_nonzeroメソッドで、値が0でない要素数をカウントできます。
書式
numpy.count_nonzero(ndarray)
■返り値
値が0でない要素数
# -*- coding: utf-8 import numpy as np # 配列生成 A = np.array([0, 1, 1, 1, 2, 0, 0]) # 値が0でない要素数をカウント num = np.count_nonzero(A) # 結果表示 print(num) # 4
|関連記事
–|–
1|■【NumPy】値が0でない要素数をカウント
whereメソッドで、条件を満たす要素番号を抽出できます。
今回はそれを用いて任意の値をもつ要素数を求めてみました。
# -*- coding: utf-8 import numpy as np # 配列生成 A = np.array([0, 1, 1, 1, 2, 0, 0]) # 値が2の要素数 num = len(np.where(A==1)[0]) # 結果表示 print(num) # 3
| – | 関連記事 |
|---|---|
| 1 | ■【NumPy】任意の値をもつ要素数をカウント |
NumPy配列では、次元数・バイト数を簡単に計算できます。
# -*- coding: utf-8 -*-
import numpy as np
# 2次元配列の宣言・初期化
A = np.array([[1, 2],
[3, 4],
[5, 6]])
# 行列の大きさ
print("行列Aの次元数:", A.ndim) # 行列Aの次元数: 2
print("行列Aのバイト数(全体):", A.nbytes) # 行列Aのバイト数(全体): 48
print("行列Aのバイト数(1要素):", A.itemsize) # 行列Aのバイト数(1要素): 8
| – | 関連記事 |
|---|---|
| 1 | ■【NumPy】配列の次元数・バイト数 |
【配列の比較】完全一致
allcloseメソッドで2つの配列を比較し、全ての要素が完全に一致するか調べることができます。
書式
numpy.allclose(ndarray)
■返り値
完全一致:True、不一致:False
# -*- coding: utf-8
import numpy as np
# 配列生成
A = np.array([[1, 0],
[0, 1]])
B = np.array([[1, 0],
[0, 1]])
# 一致判定
flag = np.allclose(A, B)
# 結果表示
print(flag) # True
| – | 関連記事 |
|---|---|
| 1 | ■【NumPy】2つの配列が完全一致するか判定 |
【高速化】Numbaモジュール
Python用数値計算ライブラリ「NumPy」の配列の要素にfor文でアクセスすると、処理速度が急低下する問題があります。
for文を使わずに「NumPyのメソッド」や「他のライブラリ」で処理を実装するのが鉄則ですがどうしてもfor文を使いたい場合があります。
そんなときは「Numba」ライブラリを使うことで元のソースコードをほとんど弄らずに高速化できます。
NumPy
#-*- coding:utf-8 -*-
import cv2
import numpy as np
import time
def filter2d(src, kernel, fill_value=-1):
# カーネルサイズ
m, n = kernel.shape
# 畳み込み演算をしない領域の幅
d = int((m-1)/2)
h, w = src.shape[0], src.shape[1]
# 出力画像用の配列
if fill_value == -1: dst = src.copy()
elif fill_value == 0: dst = np.zeros((h, w))
else:
dst = np.zeros((h, w))
dst.fill(fill_value)
for y in range(d, h - d):
for x in range(d, w - d):
# 畳み込み演算
dst[y][x] = np.sum(src[y-d:y+d+1, x-d:x+d+1]*kernel)
return dst
def main():
# 入力画像をグレースケールで読み込み
gray = cv2.imread("input2.jpg", 0)
# 処理開始時間の計測
start = time.time()
# カーネル(縦方向の輪郭検出用)
kernel = np.array([[1/9, 1/9, 1/9],
[1/9, 1/9, 1/9],
[1/9, 1/9, 1/9]])
# 方法1(NumPyで実装)
dst1 = filter2d(gray, kernel, -1)
# 処理終了時刻の計測
end = time.time()
# 処理時間の表示
print("処理時間" + str(end-start) + "[sec]")
# 結果を出力
cv2.imwrite("output1.jpg", dst1)
if __name__ == "__main__":
main()
NumPy+Numba
#-*- coding:utf-8 -*-
import cv2
import numpy as np
import time
import numba
@numba.jit
def filter2d(src, kernel, fill_value=-1):
# カーネルサイズ
m, n = kernel.shape
# 畳み込み演算をしない領域の幅
d = int((m-1)/2)
h, w = src.shape[0], src.shape[1]
# 出力画像用の配列
if fill_value == -1: dst = src.copy()
elif fill_value == 0: dst = np.zeros((h, w))
else:
dst = np.zeros((h, w))
dst.fill(fill_value)
for y in range(d, h - d):
for x in range(d, w - d):
# 畳み込み演算
dst[y][x] = np.sum(src[y-d:y+d+1, x-d:x+d+1]*kernel)
return dst
def main():
# 入力画像をグレースケールで読み込み
gray = cv2.imread("input2.jpg", 0)
# 処理開始時間の計測
start = time.time()
# カーネル(縦方向の輪郭検出用)
kernel = np.array([[1/9, 1/9, 1/9],
[1/9, 1/9, 1/9],
[1/9, 1/9, 1/9]])
# 方法1(NumPyで実装)
dst1 = filter2d(gray, kernel, -1)
# 処理終了時刻の計測
end = time.time()
# 処理時間の表示
print("処理時間" + str(end-start) + "[sec]")
# 結果を出力
cv2.imwrite("output1.jpg", dst1)
if __name__ == "__main__":
main()
OpenCV
#-*- coding:utf-8 -*-
import cv2
import numpy as np
import time
def main():
# 入力画像をグレースケールで読み込み
gray = cv2.imread("input.jpg", 0)
# 処理開始時間の計測
start = time.time()
# 方法3(OpenCVで実装)
dst3 = cv2.blur(gray, ksize=(3,3))
# 処理終了時刻の計測
end = time.time()
# 処理時間の表示
print("処理時間" + str(end-start) + "[sec]")
# 結果を出力
cv2.imwrite("output3.jpg", dst3)
if __name__ == "__main__":
main()
結果は以下の通りになりました。
■実行環境
| 項目 | 説明 |
|---|---|
| 入力画像 | グレースケール画像(440×450[px]) |
| OS | Windows10 Home Premium 64bit |
| メモリ容量 | 4GB |
| CPU | Core i3-2330M 2.20GHz |
■結果
| – | 処理速度[sec] |
|---|---|
| NumPy | 3.2753376960754395[sec] |
| NumPy+Numba | 1.225313425064087[sec] |
| OpenCV | 0.13230109214782715[sec] |
Numbaを使うと3倍くらい速くなりました。
ただし、今回の画像処理の場合ではOpenCVの方がさらに10倍程度速くなりました。
NumbaはGPUを使うなど色々な設定が出来るので、もうちょっと弄ればより速くなると思います。
| – | 関連記事 |
|---|---|
| 1 | ■【Numba】NumPy + for文の高速化 |
| – | 関連記事 |
|---|---|
| 1 | ■Python入門 サンプル集 |
| 2 | ■NumPy入門 サンプル集 |

コメント