Skip to content

100 NumPy 練習問題(日本語訳)

このページは、Nicolas P. Rougier 氏による 100 numpy exercises の日本語訳です。第 4 回「データ操作の基礎 - NumPy」の補助教材として、自学自習用にご利用ください。

出典・ライセンス

  • 原典: rougier/numpy-100
  • 著作権: Copyright (c) 2016-2024 Nicolas P. Rougier
  • ライセンス: MIT License
  • 翻訳: 茨城大学「データ活用法」講義(非公式日本語訳)
  • 翻訳方法: 本ページの日本語訳は AI(大規模言語モデル)を用いて作成しています。誤訳や不自然な表現が含まれる可能性があるため、疑問がある場合は原典を参照してください。

使い方

100 問の NumPy 練習問題が、基本操作から応用までおおむね難易度順に並んでいます。各問題には 「ヒント」 と 「解答」 のアコーディオンがあり、クリックすると展開できます。

  1. まず問題文だけを読んで、自分で書いてみる
  2. 詰まったらヒントを開いて、関数名や考え方を確認する
  3. 答え合わせに解答を開く

すべての問題に取り組む必要はありません。気になるものから挑戦してみてください。

準備
import numpy as np

1. NumPy パッケージを np という名前でインポートしてください ★☆☆

ヒント

import … as

解答
import numpy as np

2. NumPy のバージョンと設定情報を表示してください ★☆☆

ヒント

np.__version__、np.show_config()

解答
print(np.__version__)
np.show_config()

3. サイズ 10 のゼロベクトル(要素がすべて 0)を作成してください ★☆☆

ヒント

np.zeros

解答
Z = np.zeros(10)
print(Z)

4. 任意の配列のメモリサイズを調べる方法は? ★☆☆

ヒント

size、itemsize

解答
Z = np.zeros((10, 10))
print("%d bytes" % (Z.size * Z.itemsize))

# よりシンプルな書き方
print("%d bytes" % Z.nbytes)

5. コマンドラインから NumPy の add 関数のドキュメントを取得する方法は? ★☆☆

ヒント

np.info

解答
%run `python -c "import numpy; numpy.info(numpy.add)"`

6. サイズ 10 のゼロベクトルを作成し、5 番目の要素だけ 1 にしてください ★☆☆

ヒント

array[4]

解答
Z = np.zeros(10)
Z[4] = 1
print(Z)

7. 10 以上 50 未満の値を持つベクトルを作成してください ★☆☆

ヒント

arange

解答
Z = np.arange(10, 50)
print(Z)

8. ベクトルを逆順にしてください(最初の要素が最後になるように)★☆☆

ヒント

array[::-1]

解答
Z = np.arange(50)
Z = Z[::-1]
print(Z)

9. 0 から 8 の値を持つ 3×3 の行列を作成してください ★☆☆

ヒント

reshape

解答
Z = np.arange(9).reshape(3, 3)
print(Z)

10. [1, 2, 0, 0, 4, 0] から非ゼロ要素のインデックスを求めてください ★☆☆

ヒント

np.nonzero

解答
nz = np.nonzero([1, 2, 0, 0, 4, 0])
print(nz)

11. 3×3 の単位行列を作成してください ★☆☆

ヒント

np.eye

解答
Z = np.eye(3)
print(Z)

12. ランダムな値を持つ 3×3×3 の配列を作成してください ★☆☆

ヒント

np.random.random

解答
Z = np.random.random((3, 3, 3))
print(Z)

13. ランダムな値を持つ 10×10 の配列を作成し、最小値と最大値を求めてください ★☆☆

ヒント

min、max

解答
Z = np.random.random((10, 10))
Zmin, Zmax = Z.min(), Z.max()
print(Zmin, Zmax)

14. サイズ 30 のランダムなベクトルを作成し、平均値を求めてください ★☆☆

ヒント

mean

解答
Z = np.random.random(30)
m = Z.mean()
print(m)

15. 縁が 1、内側が 0 の 2 次元配列を作成してください ★☆☆

ヒント

array[1:-1, 1:-1]

解答
Z = np.ones((10, 10))
Z[1:-1, 1:-1] = 0
print(Z)

16. 既存の配列の周囲に 0 で埋めた縁を追加する方法は? ★☆☆

ヒント

np.pad

解答
Z = np.ones((5, 5))
Z = np.pad(Z, pad_width=1, mode='constant', constant_values=0)
print(Z)

# この問題の解答ではないが、覚えておくと便利:fancy indexing による in-place な書き換え
Z[:, [0, -1]] = 0
Z[[0, -1], :] = 0
print(Z)

17. 次の式の結果は何になりますか? ★☆☆

0 * np.nan
np.nan == np.nan
np.inf > np.nan
np.nan - np.nan
np.nan in set([np.nan])
0.3 == 3 * 0.1
ヒント

NaN = not a number(数ではない)、inf = infinity(無限大)

解答
print(0 * np.nan)
print(np.nan == np.nan)
print(np.inf > np.nan)
print(np.nan - np.nan)
print(np.nan in set([np.nan]))
print(0.3 == 3 * 0.1)

18. 対角線のすぐ下に値 1, 2, 3, 4 を持つ 5×5 の行列を作成してください ★☆☆

ヒント

np.diag

解答
Z = np.diag(1 + np.arange(4), k=-1)
print(Z)

19. 8×8 の行列を作成し、チェッカーボード(市松模様)のパターンで埋めてください ★☆☆

ヒント

array[::2]

解答
Z = np.zeros((8, 8), dtype=int)
Z[1::2, ::2] = 1
Z[::2, 1::2] = 1
print(Z)

20. 形状 (6, 7, 8) の配列があるとき、100 番目の要素のインデックス (x, y, z) は何になりますか? ★☆☆

ヒント

np.unravel_index

解答
print(np.unravel_index(99, (6, 7, 8)))

21. tile 関数を使って 8×8 のチェッカーボード行列を作成してください ★☆☆

ヒント

np.tile

解答
Z = np.tile(np.array([[0, 1], [1, 0]]), (4, 4))
print(Z)

22. 5×5 のランダム行列を正規化(標準化)してください ★☆☆

ヒント

(x - mean) / std

解答
Z = np.random.random((5, 5))
Z = (Z - np.mean(Z)) / (np.std(Z))
print(Z)

23. 4 つの符号なしバイト(RGBA)として色を表現するカスタム dtype を作成してください ★☆☆

ヒント

np.dtype

解答
color = np.dtype([("r", np.ubyte),
                  ("g", np.ubyte),
                  ("b", np.ubyte),
                  ("a", np.ubyte)])

24. 5×3 の行列と 3×2 の行列の行列積を求めてください(通常の行列の積)★☆☆

ヒント

(ヒントなし)

解答
Z = np.matmul(np.ones((5, 3)), np.ones((3, 2)))
print(Z)

# 別解(Python 3.5 以上)
Z = np.ones((5, 3)) @ np.ones((3, 2))
print(Z)

25. 1 次元配列に対し、3 より大きく 8 より小さい要素をその場で(in-place)負の値にしてください ★☆☆

ヒント

>、<

解答
# Author: Evgeni Burovski

Z = np.arange(11)
Z[(3 < Z) & (Z < 8)] *= -1
print(Z)

26. 次のスクリプトの出力は何になりますか? ★☆☆

# Author: Jake VanderPlas

print(sum(range(5), -1))
from numpy import *
print(sum(range(5), -1))
ヒント

np.sum

解答
# Author: Jake VanderPlas

print(sum(range(5), -1))
from numpy import *
print(sum(range(5), -1))

27. 整数ベクトル Z を考えるとき、次の式のうち合法(エラーにならない)なのはどれですか? ★☆☆

Z**Z
2 << Z >> 2
Z <- Z
1j*Z
Z/1/1
Z<Z>Z
ヒント

(ヒントなし)

解答
Z**Z
2 << Z >> 2
Z <- Z
1j*Z
Z/1/1
Z<Z>Z

28. 次の式の結果は何になりますか? ★☆☆

np.array(0) / np.array(0)
np.array(0) // np.array(0)
np.array([np.nan]).astype(int).astype(float)
ヒント

(ヒントなし)

解答
print(np.array(0) / np.array(0))
print(np.array(0) // np.array(0))
print(np.array([np.nan]).astype(int).astype(float))

29. 浮動小数点配列の値を「0 から離れる方向」に丸める方法は? ★☆☆

ヒント

np.uniform、np.copysign、np.ceil、np.abs、np.where

解答
# Author: Charles R Harris

Z = np.random.uniform(-10, +10, 10)
print(np.copysign(np.ceil(np.abs(Z)), Z))

# 読みやすいが効率は劣る別解
print(np.where(Z > 0, np.ceil(Z), np.floor(Z)))

30. 2 つの配列の共通の値を求める方法は? ★☆☆

ヒント

np.intersect1d

解答
Z1 = np.random.randint(0, 10, 10)
Z2 = np.random.randint(0, 10, 10)
print(np.intersect1d(Z1, Z2))

31. NumPy の警告をすべて無視する方法は?(非推奨)★☆☆

ヒント

np.seterr、np.errstate

解答
# 警告を無効化
defaults = np.seterr(all="ignore")
Z = np.ones(1) / 0

# 元に戻す
_ = np.seterr(**defaults)

# コンテキストマネージャを使う方法
with np.errstate(all="ignore"):
    np.arange(3) / 0

32. 次の式は真ですか? ★☆☆

np.sqrt(-1) == np.emath.sqrt(-1)
ヒント

虚数

解答
np.sqrt(-1) == np.emath.sqrt(-1)

33. 昨日・今日・明日の日付を取得する方法は? ★☆☆

ヒント

np.datetime64、np.timedelta64

解答
yesterday = np.datetime64('today') - np.timedelta64(1)
today     = np.datetime64('today')
tomorrow  = np.datetime64('today') + np.timedelta64(1)

34. 2016 年 7 月のすべての日付を取得する方法は? ★★☆

ヒント

np.arange(dtype=datetime64['D'])

解答
Z = np.arange('2016-07', '2016-08', dtype='datetime64[D]')
print(Z)

35. ((A + B) * (-A / 2)) をコピーなしで(in-place で)計算する方法は? ★★☆

ヒント

np.add(out=)、np.negative(out=)、np.multiply(out=)、np.divide(out=)

解答
A = np.ones(3) * 1
B = np.ones(3) * 2
np.add(A, B, out=B)
np.divide(A, 2, out=A)
np.negative(A, out=A)
np.multiply(A, B, out=A)

36. 正の数からなるランダム配列の整数部分を、4 つの異なる方法で取り出してください ★★☆

ヒント

%、np.floor、astype、np.trunc

解答
Z = np.random.uniform(0, 10, 10)

print(Z - Z % 1)
print(Z // 1)
print(np.floor(Z))
print(Z.astype(int))
print(np.trunc(Z))

37. 各行が 0〜4 の値を持つ 5×5 の行列を作成してください ★★☆

ヒント

np.arange

解答
Z = np.zeros((5, 5))
Z += np.arange(5)
print(Z)

# ブロードキャストを使わない別解
Z = np.tile(np.arange(0, 5), (5, 1))
print(Z)

38. 10 個の整数を生成するジェネレータ関数を考え、それを用いて配列を作成してください ★☆☆

ヒント

np.fromiter

解答
def generate():
    for x in range(10):
        yield x
Z = np.fromiter(generate(), dtype=float, count=-1)
print(Z)

39. 0 と 1 の両方を除いた値を持つ、サイズ 10 のベクトルを作成してください ★★☆

ヒント

np.linspace

解答
Z = np.linspace(0, 1, 11, endpoint=False)[1:]
print(Z)

40. サイズ 10 のランダムベクトルを作成し、ソートしてください ★★☆

ヒント

sort

解答
Z = np.random.random(10)
Z.sort()
print(Z)

41. 小さい配列を np.sum より高速に合計する方法は? ★★☆

ヒント

np.add.reduce

解答
# Author: Evgeni Burovski

Z = np.arange(10)
np.add.reduce(Z)

42. 2 つのランダムな配列 A、B が等しいかどうかを確認してください ★★☆

ヒント

np.allclose、np.array_equal

解答
A = np.random.randint(0, 2, 5)
B = np.random.randint(0, 2, 5)

# 配列の形状が同じで、値の比較に許容誤差を許す場合
equal = np.allclose(A, B)
print(equal)

# 形状も要素も完全に一致するかをチェック(許容誤差なし)
equal = np.array_equal(A, B)
print(equal)

43. 配列を書き換え不可(読み取り専用)にしてください ★★☆

ヒント

flags.writeable

解答
Z = np.zeros(10)
Z.flags.writeable = False
Z[0] = 1

44. 直交座標を表すランダムな 10×2 行列を考え、それを極座標に変換してください ★★☆

ヒント

np.sqrt、np.arctan2

解答
Z = np.random.random((10, 2))
X, Y = Z[:, 0], Z[:, 1]
R = np.sqrt(X**2 + Y**2)
T = np.arctan2(Y, X)
print(R)
print(T)

45. サイズ 10 のランダムベクトルを作成し、最大値を 0 に置き換えてください ★★☆

ヒント

argmax

解答
Z = np.random.random(10)
Z[Z.argmax()] = 0
print(Z)

46. [0, 1] × [0, 1] の領域を覆う x と y 座標を持つ構造化配列を作成してください ★★☆

ヒント

np.meshgrid

解答
Z = np.zeros((5, 5), [('x', float), ('y', float)])
Z['x'], Z['y'] = np.meshgrid(np.linspace(0, 1, 5),
                             np.linspace(0, 1, 5))
print(Z)

47. 2 つの配列 X と Y が与えられたとき、コーシー行列 C(Cij = 1 / (xi - yj))を構成してください ★★☆

ヒント

np.subtract.outer

解答
# Author: Evgeni Burovski

X = np.arange(8)
Y = X + 0.5
C = 1.0 / np.subtract.outer(X, Y)
print(np.linalg.det(C))

48. NumPy の各スカラ型について、表現可能な最小値と最大値を表示してください ★★☆

ヒント

np.iinfo、np.finfo、eps

解答
for dtype in [np.int8, np.int32, np.int64]:
    print(np.iinfo(dtype).min)
    print(np.iinfo(dtype).max)
for dtype in [np.float32, np.float64]:
    print(np.finfo(dtype).min)
    print(np.finfo(dtype).max)
    print(np.finfo(dtype).eps)

49. 配列のすべての値を省略せずに表示する方法は? ★★☆

ヒント

np.set_printoptions

解答
np.set_printoptions(threshold=float("inf"))
Z = np.zeros((40, 40))
print(Z)

50. ベクトル内で、与えられたスカラ値に最も近い値を見つける方法は? ★★☆

ヒント

argmin

解答
Z = np.arange(100)
v = np.random.uniform(0, 100)
index = (np.abs(Z - v)).argmin()
print(Z[index])

51. 位置 (x, y) と色 (r, g, b) を表す構造化配列を作成してください ★★☆

ヒント

dtype

解答
Z = np.zeros(10, [('position', [('x', float, 1),
                                ('y', float, 1)]),
                  ('color',    [('r', float, 1),
                                ('g', float, 1),
                                ('b', float, 1)])])
print(Z)

52. 形状 (100, 2) のランダムベクトル(座標)を考え、点と点の間の距離を求めてください ★★☆

ヒント

np.atleast_2d、T、np.sqrt

解答
Z = np.random.random((10, 2))
X, Y = np.atleast_2d(Z[:, 0], Z[:, 1])
D = np.sqrt((X - X.T)**2 + (Y - Y.T)**2)
print(D)

# scipy を使うとさらに高速
import scipy
import scipy.spatial

Z = np.random.random((10, 2))
D = scipy.spatial.distance.cdist(Z, Z)
print(D)

53. 32 ビット浮動小数点配列を、32 ビット整数配列にその場で(in-place)変換する方法は? ★★☆

ヒント

view と [:] =

解答
Z = (np.random.rand(10) * 100).astype(np.float32)
Y = Z.view(np.int32)
Y[:] = Z
print(Y)

54. 次のようなファイルを読み込む方法は? ★★☆

1, 2, 3, 4, 5
6,  ,  , 7, 8
 ,  , 9,10,11
ヒント

np.genfromtxt

解答
from io import StringIO

# 疑似ファイル
s = StringIO('''1, 2, 3, 4, 5

                6,  ,  , 7, 8

                 ,  , 9,10,11
''')
Z = np.genfromtxt(s, delimiter=",", dtype=int, filling_values=0)
print(Z)

55. NumPy 配列に対する enumerate の等価物は? ★★☆

ヒント

np.ndenumerate、np.ndindex

解答
Z = np.arange(9).reshape(3, 3)
for index, value in np.ndenumerate(Z):
    print(index, value)
for index in np.ndindex(Z.shape):
    print(index, Z[index])

56. 一般的な 2 次元ガウス関数風の配列を生成してください ★★☆

ヒント

np.meshgrid、np.exp

解答
X, Y = np.meshgrid(np.linspace(-1, 1, 10), np.linspace(-1, 1, 10))
sigma, mu = 1.0, 0.0
G = np.exp(-((X - mu) ** 2 + (Y - mu) ** 2) / (2.0 * sigma**2))
print(G)

# 2 次元ガウスが分離可能であることを利用した別解
# Author: Nin17
x = np.linspace(-1, 1, 10)
y = np.linspace(-1, 1, 10)
gx = np.exp(-((x - mu) ** 2 / (2.0 * sigma**2)))
gy = np.exp(-((y - mu) ** 2 / (2.0 * sigma**2)))
G = gy[:, None] * gx[None, :]
print(G)

57. 2 次元配列に p 個の要素をランダムに配置する方法は? ★★☆

ヒント

np.put、np.random.choice

解答
# Author: Divakar

n = 10
p = 3
Z = np.zeros((n, n))
np.put(Z, np.random.choice(range(n * n), p, replace=False), 1)
print(Z)

58. 行列の各行から、その行の平均値を引いてください ★★☆

ヒント

mean(axis=, keepdims=)

解答
# Author: Warren Weckesser

X = np.random.rand(5, 10)

# 最近の NumPy
Y = X - X.mean(axis=1, keepdims=True)

# 古い NumPy
Y = X - X.mean(axis=1).reshape(-1, 1)

print(Y)

59. 配列を n 番目の列でソートする方法は? ★★☆

ヒント

argsort

解答
# Author: Steve Tjoa

Z = np.random.randint(0, 10, (3, 3))
print(Z)
print(Z[Z[:, 1].argsort()])

60. 与えられた 2 次元配列に「ゼロのみの列」があるかを調べる方法は? ★★☆

ヒント

any、~

解答
# Author: Warren Weckesser

# ゼロ : 0
Z = np.random.randint(0, 3, (3, 10))
print((~Z.any(axis=0)).any())

# ゼロ : np.nan
Z = np.array([
    [0, 1, np.nan],
    [1, 2, np.nan],
    [4, 5, np.nan]
])
print(np.isnan(Z).all(axis=0))

61. 配列の中から、与えられた値に最も近い値を見つけてください ★★☆

ヒント

np.abs、argmin、flat

解答
Z = np.random.uniform(0, 1, 10)
z = 0.5
m = Z.flat[np.abs(Z - z).argmin()]
print(m)

62. 形状 (1, 3) と (3, 1) の 2 つの配列を考え、イテレータを使ってその合計を計算する方法は? ★★☆

ヒント

np.nditer

解答
A = np.arange(3).reshape(3, 1)
B = np.arange(3).reshape(1, 3)
it = np.nditer([A, B, None])
for x, y, z in it: z[...] = x + y
print(it.operands[2])

63. name 属性を持つ配列クラスを作成してください ★★☆

ヒント

クラスメソッド

解答
class NamedArray(np.ndarray):
def **new**(cls, array, name="no name"):
obj = np.asarray(array).view(cls)
obj.name = name
return obj
def **array_finalize**(self, obj):
if obj is None: return
self.name = getattr(obj, 'name', "no name")

Z = NamedArray(np.arange(10), "range_10")
print(Z.name)

64. 与えられたベクトルに対し、別のベクトルのインデックスで指定された各要素に 1 を加える方法は?(重複インデックスに注意)★★★

ヒント

np.bincount または np.add.at

解答
# Author: Brett Olsen

Z = np.ones(10)
I = np.random.randint(0, len(Z), 20)
Z += np.bincount(I, minlength=len(Z))
print(Z)

# 別解
# Author: Bartosz Telenczuk
np.add.at(Z, I, 1)
print(Z)

65. インデックスリスト I に基づいて、ベクトル X の要素を配列 F に累積する方法は? ★★★

ヒント

np.bincount

解答
# Author: Alan G Isaac

X = [1, 2, 3, 4, 5, 6]
I = [1, 3, 9, 3, 4, 1]
F = np.bincount(I, X)
print(F)

66. dtype が ubyte の (w, h, 3) 画像に対し、ユニークな色の数を計算してください ★★☆

ヒント

np.unique

解答
# Author: Fisher Wang

w, h = 256, 256
I = np.random.randint(0, 4, (h, w, 3)).astype(np.ubyte)
colors = np.unique(I.reshape(-1, 3), axis=0)
n = len(colors)
print(n)

# 高速版
# Author: Mark Setchell
# https://stackoverflow.com/a/59671950/2836621

w, h = 256, 256
I = np.random.randint(0, 4, (h, w, 3), dtype=np.uint8)

# 各ピクセルを 3 つの 8 ビットではなく、1 つの 24 ビット整数として扱う
I24 = np.dot(I.astype(np.uint32), [1, 256, 65536])

# ユニークな色を数える
n = len(np.unique(I24))
print(n)

67. 4 次元配列を考えるとき、最後の 2 軸の合計を一度に取る方法は? ★★★

ヒント

sum(axis=(-2, -1))

解答
A = np.random.randint(0, 10, (3, 4, 3, 4))
# 軸のタプルを渡す方法(NumPy 1.7.0 で導入)
sum = A.sum(axis=(-2, -1))
print(sum)
# 最後の 2 次元を 1 次元に平坦化する方法
# (axis 引数にタプルを受け付けない関数で便利)
sum = A.reshape(A.shape[:-2] + (-1,)).sum(axis=-1)
print(sum)

68. 1 次元ベクトル D と同じサイズのベクトル S(サブセットのインデックス)が与えられたとき、D のサブセットごとの平均を計算する方法は? ★★★

ヒント

np.bincount

解答
# Author: Jaime Fernández del Río

D = np.random.uniform(0, 1, 100)
S = np.random.randint(0, 10, 100)
D_sums = np.bincount(S, weights=D)
D_counts = np.bincount(S)
D_means = D_sums / D_counts
print(D_means)

# 参考:pandas を使うとより直感的に書ける
import pandas as pd
print(pd.Series(D).groupby(S).mean())

69. 行列積の対角成分を取得する方法は? ★★★

ヒント

np.diag

解答
# Author: Mathieu Blondel

A = np.random.uniform(0, 1, (5, 5))
B = np.random.uniform(0, 1, (5, 5))

# 遅い版
np.diag(np.dot(A, B))

# 速い版
np.sum(A * B.T, axis=1)

# さらに速い版
np.einsum("ij,ji->i", A, B)

70. ベクトル [1, 2, 3, 4, 5] を考え、各値の間に 0 を 3 個ずつ挿入した新しいベクトルを作成してください ★★★

ヒント

array[::4]

解答
# Author: Warren Weckesser

Z = np.array([1, 2, 3, 4, 5])
nz = 3
Z0 = np.zeros(len(Z) + (len(Z) - 1) * nz)
Z0[::nz + 1] = Z
print(Z0)

71. 次元 (5, 5, 3) の配列に、次元 (5, 5) の配列を乗ずる方法は? ★★★

ヒント

array[:, :, None]

解答
A = np.ones((5, 5, 3))
B = 2 * np.ones((5, 5))
print(A * B[:, :, None])

72. 配列の 2 つの行を入れ替える方法は? ★★★

ヒント

array[[]] = array[[]]

解答
# Author: Eelco Hoogendoorn

A = np.arange(25).reshape(5, 5)
A[[0, 1]] = A[[1, 0]]
print(A)

73. 10 個の三角形(頂点を共有する)を表す 10 個の 3 つ組を考え、すべての三角形を構成するユニークな線分の集合を求めてください ★★★

ヒント

repeat、np.roll、np.sort、view、np.unique

解答
# Author: Nicolas P. Rougier

faces = np.random.randint(0, 100, (10, 3))
F = np.roll(faces.repeat(2, axis=1), -1, axis=1)
F = F.reshape(len(F) * 3, 2)
F = np.sort(F, axis=1)
G = F.view(dtype=[('p0', F.dtype), ('p1', F.dtype)])
G = np.unique(G)
print(G)

74. ソート済みの bincount 配列 C が与えられたとき、np.bincount(A) == C となる配列 A を作成する方法は? ★★★

ヒント

np.repeat

解答
# Author: Jaime Fernández del Río

C = np.bincount([1, 1, 2, 3, 4, 4, 6])
A = np.repeat(np.arange(len(C)), C)
print(A)

75. 配列に対してスライディングウィンドウで平均を計算する方法は? ★★★

ヒント

np.cumsum、または from numpy.lib.stride_tricks import sliding_window_view(NumPy 1.20.0 以降)

解答
# Author: Jaime Fernández del Río

def moving_average(a, n=3):
    ret = np.cumsum(a, dtype=float)
    ret[n:] = ret[n:] - ret[:-n]
    return ret[n - 1:] / n
Z = np.arange(20)
print(moving_average(Z, n=3))

# Author: Jeff Luo (@Jeff1999)
# NumPy 1.20.0 以降が必要

from numpy.lib.stride_tricks import sliding_window_view

Z = np.arange(20)
print(sliding_window_view(Z, window_shape=3).mean(axis=-1))

76. 1 次元配列 Z を考え、最初の行が (Z[0], Z[1], Z[2])、各行が 1 ずつシフトする 2 次元配列を作成してください(最後の行は (Z[-3], Z[-2], Z[-1]))★★★

ヒント

from numpy.lib import stride_tricks、または from numpy.lib.stride_tricks import sliding_window_view(NumPy 1.20.0 以降)

解答
# Author: Joe Kington / Erik Rigtorp
from numpy.lib import stride_tricks

def rolling(a, window):
    shape = (a.size - window + 1, window)
    strides = (a.strides[0], a.strides[0])
    return stride_tricks.as_strided(a, shape=shape, strides=strides)
Z = rolling(np.arange(10), 3)
print(Z)

# Author: Jeff Luo (@Jeff1999)

Z = np.arange(10)
print(sliding_window_view(Z, window_shape=3))

77. ブール値を否定したり、浮動小数点数の符号を in-place で反転する方法は? ★★★

ヒント

np.logical_not、np.negative

解答
# Author: Nathaniel J. Smith

Z = np.random.randint(0, 2, 100)
np.logical_not(Z, out=Z)

Z = np.random.uniform(-1.0, 1.0, 100)
np.negative(Z, out=Z)

78. 2 次元の直線を表す 2 つの点群 P0、P1 と点 p を考えるとき、p から各直線 i (P0[i], P1[i]) までの距離を計算する方法は? ★★★

ヒント

(ヒントなし)

解答
P0 = np.random.uniform(-10, 10, (10, 2))
P1 = np.random.uniform(-10, 10, (10, 2))
p = np.random.uniform(-10, 10, (1, 2))

def distance_faster(P0, P1, p):
    # Author: Hemanth Pasupuleti
    # Reference: https://mathworld.wolfram.com/Point-LineDistance2-Dimensional.html

    v = P1 - P0
    v[:, [0, 1]] = v[:, [1, 0]]
    v[:, 1] *= -1
    norm = np.linalg.norm(v, axis=1)
    r = P0 - p
    d = np.abs(np.einsum("ij,ij->i", r, v)) / norm

    return d

print(distance_faster(P0, P1, p))

##--------------- または ---------------##
def distance_slower(P0, P1, p):
    T = P1 - P0
    L = (T**2).sum(axis=1)
    U = -((P0[:, 0] - p[..., 0]) * T[:, 0] + (P0[:, 1] - p[..., 1]) * T[:, 1]) / L
    U = U.reshape(len(U), 1)
    D = P0 + U * T - p
    return np.sqrt((D**2).sum(axis=1))

print(distance_slower(P0, P1, p))

79. 2 次元直線を表す 2 つの点群 P0、P1 と、点群 P を考えるとき、各点 j (P[j]) から各直線 i (P0[i], P1[i]) までの距離を計算する方法は? ★★★

ヒント

(ヒントなし)

解答
# Author: Italmassov Kuanysh

# 前の問題の distance 関数を利用
P0 = np.random.uniform(-10, 10, (10, 2))
P1 = np.random.uniform(-10, 10, (10, 2))
p = np.random.uniform(-10, 10, (10, 2))
print(np.array([distance(P0, P1, p_i) for p_i in p]))

# Author: Yang Wu(ブロードキャストを使う方法)
def distance_points_to_lines(p: np.ndarray, p_1: np.ndarray, p_2: np.ndarray) -> np.ndarray:
    x_0, y_0 = p.T  # 形状 -> (n points, )
    x_1, y_1 = p_1.T  # 形状 -> (n lines, )
    x_2, y_2 = p_2.T  # 形状 -> (n lines, )

    # p_1 -> p_2 への変位ベクトル
    dx = x_2 - x_1  # 形状 -> (n lines, )
    dy = y_2 - y_1  # 形状 -> (n lines, )

    # 「外積」項
    cross_term = x_2 * y_1 - y_2 * x_1  # 形状 -> (n lines, )

    # x_0, y_0 (n points, 1) と dx, dy, cross_term (1, n lines) をブロードキャスト
    numerator = np.abs(
        dy[np.newaxis, :] * x_0[:, np.newaxis]
        - dx[np.newaxis, :] * y_0[:, np.newaxis]
        + cross_term[np.newaxis, :]
    )
    denominator = np.sqrt(dx**2 + dy**2)  # 形状 -> (n lines, )

    # (n points, n lines) / (1, n lines) -> (n points, n lines)
    return numerator / denominator[np.newaxis, :]

distance_points_to_lines(p, P0, P1)

80. 任意の配列を考え、指定した要素を中心とする固定形状の部分配列を取り出す関数を書いてください(必要に応じて fill 値でパディング)★★★

ヒント

minimum、maximum

解答
# Author: Nicolas Rougier

Z = np.random.randint(0, 10, (10, 10))
shape = (5, 5)
fill  = 0
position = (1, 1)

R = np.ones(shape, dtype=Z.dtype) * fill
P  = np.array(list(position)).astype(int)
Rs = np.array(list(R.shape)).astype(int)
Zs = np.array(list(Z.shape)).astype(int)

R_start = np.zeros((len(shape),)).astype(int)
R_stop  = np.array(list(shape)).astype(int)
Z_start = (P - Rs // 2)
Z_stop  = (P + Rs // 2) + Rs % 2

R_start = (R_start - np.minimum(Z_start, 0)).tolist()
Z_start = (np.maximum(Z_start, 0)).tolist()
R_stop = np.maximum(R_start, (R_stop - np.maximum(Z_stop - Zs, 0))).tolist()
Z_stop = (np.minimum(Z_stop, Zs)).tolist()

r = tuple([slice(start, stop) for start, stop in zip(R_start, R_stop)])
z = tuple([slice(start, stop) for start, stop in zip(Z_start, Z_stop)])
R[r] = Z[z]
print(Z)
print(R)

81. 配列 Z = [1, 2, ..., 14] から、R = [[1,2,3,4], [2,3,4,5], ..., [11,12,13,14]] のような配列を生成する方法は? ★★★

ヒント

stride_tricks.as_strided、または sliding_window_view(NumPy 1.20.0 以降)

解答
# Author: Stefan van der Walt

Z = np.arange(1, 15, dtype=np.uint32)
R = stride_tricks.as_strided(Z, (11, 4), (4, 4))
print(R)

# Author: Jeff Luo (@Jeff1999)

Z = np.arange(1, 15, dtype=np.uint32)
print(sliding_window_view(Z, window_shape=4))

82. 行列のランクを計算してください ★★★

ヒント

np.linalg.svd、np.linalg.matrix_rank

解答
# Author: Stefan van der Walt

Z = np.random.uniform(0, 1, (10, 10))
U, S, V = np.linalg.svd(Z)  # 特異値分解
threshold = len(S) * S.max() * np.finfo(S.dtype).eps
rank = np.sum(S > threshold)
print(rank)

# 別解
# Author: Jeff Luo (@Jeff1999)

rank = np.linalg.matrix_rank(Z)
print(rank)

83. 配列の中で最も頻繁に現れる値を見つける方法は? ★★★

ヒント

np.bincount、argmax

解答
Z = np.random.randint(0, 10, 50)
print(np.bincount(Z).argmax())

84. 10×10 のランダム行列から、連続した 3×3 のブロックをすべて取り出してください ★★★

ヒント

stride_tricks.as_strided、または sliding_window_view(NumPy 1.20.0 以降)

解答
# Author: Chris Barker

Z = np.random.randint(0, 5, (10, 10))
n = 3
i = 1 + (Z.shape[0] - 3)
j = 1 + (Z.shape[1] - 3)
C = stride_tricks.as_strided(Z, shape=(i, j, n, n), strides=Z.strides + Z.strides)
print(C)

# Author: Jeff Luo (@Jeff1999)

Z = np.random.randint(0, 5, (10, 10))
print(sliding_window_view(Z, window_shape=(3, 3)))

85. Z[i, j] == Z[j, i] となる 2 次元配列サブクラスを作成してください ★★★

ヒント

クラスメソッド

解答
# Author: Eric O. Lebigot # 注: 2 次元配列で、インデックスによる値の代入のみ動作

class Symetric(np.ndarray):
    def __setitem__(self, index, value):
        i, j = index
        super(Symetric, self).__setitem__((i, j), value)
        super(Symetric, self).__setitem__((j, i), value)

def symetric(Z):
    return np.asarray(Z + Z.T - np.diag(Z.diagonal())).view(Symetric)

S = symetric(np.random.randint(0, 10, (5, 5)))
S[2, 3] = 42
print(S)

86. 形状 (n, n) の行列 p 個と、形状 (n, 1) のベクトル p 個を考えるとき、p 個の行列積の和を一度に計算する方法は?(結果の形状は (n, 1))★★★

ヒント

np.tensordot

解答
# Author: Stefan van der Walt

p, n = 10, 20
M = np.ones((p, n, n))
V = np.ones((p, n, 1))
S = np.tensordot(M, V, axes=[[0, 2], [0, 1]])
print(S)

# M は (p, n, n)
# V は (p, n, 1)
# 軸 0 と 0、軸 2 と 1 をそれぞれペアで和を取ることで、(n, 1) のベクトルが残る

87. 16×16 の配列を考えるとき、ブロックサイズ 4×4 のブロック単位の和を取得する方法は? ★★★

ヒント

np.add.reduceat、または sliding_window_view(NumPy 1.20.0 以降)

解答
# Author: Robert Kern

Z = np.ones((16, 16))
k = 4
S = np.add.reduceat(np.add.reduceat(Z, np.arange(0, Z.shape[0], k), axis=0),
                                      np.arange(0, Z.shape[1], k), axis=1)
print(S)

# 別解
# Author: Sebastian Wallkötter (@FirefoxMetzger)

Z = np.ones((16, 16))
k = 4

windows = np.lib.stride_tricks.sliding_window_view(Z, (k, k))
S = windows[::k, ::k, ...].sum(axis=(-2, -1))

# さらに別解(by @Gattocrucco)
S = Z.reshape(4, 4, 4, 4).sum((1, 3))

88. NumPy 配列を使って「ライフゲーム」を実装する方法は? ★★★

ヒント

(ヒントなし)

解答
# Author: Nicolas Rougier

def iterate(Z):
    # 隣接セル数を数える
    N = (Z[0:-2, 0:-2] + Z[0:-2, 1:-1] + Z[0:-2, 2:] +
         Z[1:-1, 0:-2]                 + Z[1:-1, 2:] +
         Z[2:  , 0:-2] + Z[2:  , 1:-1] + Z[2:  , 2:])

    # ルールを適用
    birth = (N == 3) & (Z[1:-1, 1:-1] == 0)
    survive = ((N == 2) | (N == 3)) & (Z[1:-1, 1:-1] == 1)
    Z[...] = 0
    Z[1:-1, 1:-1][birth | survive] = 1
    return Z

Z = np.random.randint(0, 2, (50, 50))
for i in range(100): Z = iterate(Z)
print(Z)

89. 配列の上位 n 個の値を取得する方法は? ★★★

ヒント

np.argsort または np.argpartition

解答
Z = np.arange(10000)
np.random.shuffle(Z)
n = 5

# 遅い
print(Z[np.argsort(Z)[-n:]])

# 速い
print(Z[np.argpartition(-Z, n)[:n]])

90. 任意個のベクトルが与えられたとき、直積(すべての要素の組み合わせ)を作成する方法は? ★★★

ヒント

np.indices

解答
# Author: Stefan Van der Walt

def cartesian(arrays):
    arrays = [np.asarray(a) for a in arrays]
    shape = (len(x) for x in arrays)

    ix = np.indices(shape, dtype=int)
    ix = ix.reshape(len(arrays), -1).T

    for n, arr in enumerate(arrays):
        ix[:, n] = arrays[n][ix[:, n]]

    return ix

print(cartesian(([1, 2, 3], [4, 5], [6, 7])))

91. 通常の配列からレコード配列を作成する方法は? ★★★

ヒント

np.core.records.fromarrays

解答
Z = np.array([("Hello", 2.5, 3),
              ("World", 3.6, 2)])
R = np.core.records.fromarrays(Z.T,
                               names='col1, col2, col3',
                               formats='S8, f8, i8')
print(R)

92. 大きなベクトル Z を考えるとき、Z の 3 乗を 3 つの異なる方法で計算してください ★★★

ヒント

np.power、*、np.einsum

解答
# Author: Ryan G.

x = np.random.rand(int(5e7))

%timeit np.power(x, 3)
%timeit x * x * x
%timeit np.einsum('i,i,i->i', x, x, x)

93. 形状 (8, 3) の配列 A と形状 (2, 2) の配列 B を考えるとき、A の各行のうち、B の各行の要素(順不同)をすべて含む行を見つけてください ★★★

ヒント

np.where

解答
# Author: Gabe Schwartz

A = np.random.randint(0, 5, (8, 3))
B = np.random.randint(0, 5, (2, 2))

C = (A[..., np.newaxis, np.newaxis] == B)
rows = np.where(C.any((3, 1)).all(1))[0]
print(rows)

94. 10×3 の行列を考えるとき、要素がすべて等しくない行を抽出してください(例: [2, 2, 3])★★★

ヒント

(ヒントなし)

解答
# Author: Robert Kern

Z = np.random.randint(0, 5, (10, 3))
print(Z)
# すべての dtype(文字列配列やレコード配列を含む)に対応する解
E = np.all(Z[:, 1:] == Z[:, :-1], axis=1)
U = Z[~E]
print(U)
# 数値配列のみに対応する解(Z の列数が任意でも動作)
U = Z[Z.max(axis=1) != Z.min(axis=1), :]
print(U)

95. 整数ベクトルを 2 進数表現の行列に変換してください ★★★

ヒント

np.unpackbits

解答
# Author: Warren Weckesser

I = np.array([0, 1, 2, 3, 15, 16, 32, 64, 128])
B = ((I.reshape(-1, 1) & (2**np.arange(8))) != 0).astype(int)
print(B[:, ::-1])

# Author: Daniel T. McDonald

I = np.array([0, 1, 2, 3, 15, 16, 32, 64, 128], dtype=np.uint8)
print(np.unpackbits(I[:, np.newaxis], axis=1))

96. 2 次元配列から、ユニークな行を抽出する方法は? ★★★

ヒント

np.ascontiguousarray または np.unique

解答
# Author: Jaime Fernández del Río

Z = np.random.randint(0, 2, (6, 3))
T = np.ascontiguousarray(Z).view(np.dtype((np.void, Z.dtype.itemsize * Z.shape[1])))
_, idx = np.unique(T, return_index=True)
uZ = Z[idx]
print(uZ)

# Author: Andreas Kouzelis
# NumPy 1.13 以降
uZ = np.unique(Z, axis=0)
print(uZ)

97. 2 つのベクトル A、B を考え、np.inner、np.outer、np.sum、np.multiply と等価な計算を np.einsum で書いてください ★★★

ヒント

np.einsum

解答
# Author: Alex Riley # 必読: http://ajcr.net/Basic-guide-to-einsum/

A = np.random.uniform(0, 1, 10)
B = np.random.uniform(0, 1, 10)

np.einsum('i->', A)        # np.sum(A)
np.einsum('i,i->i', A, B)  # A * B
np.einsum('i,i', A, B)     # np.inner(A, B)
np.einsum('i,j->ij', A, B) # np.outer(A, B)

98. 2 つのベクトル (X, Y) で表される経路を、等間隔のサンプル点でサンプリングする方法は? ★★★

ヒント

np.cumsum、np.interp

解答
# Author: Bas Swinckels

phi = np.arange(0, 10 * np.pi, 0.1)
a = 1
x = a * phi * np.cos(phi)
y = a * phi * np.sin(phi)

dr = (np.diff(x)**2 + np.diff(y)**2)**.5  # 区間の長さ
r = np.zeros_like(x)
r[1:] = np.cumsum(dr)                  # 経路を積分
r_int = np.linspace(0, r.max(), 200)   # 等間隔の経路
x_int = np.interp(r_int, r, x)
y_int = np.interp(r_int, r, y)

99. 整数 n と 2 次元配列 X が与えられたとき、X の行のうち「自由度 n の多項分布からのサンプル」とみなせる行(整数のみを含み、合計が n になる行)を選んでください ★★★

ヒント

np.logical_and.reduce、np.mod

解答
# Author: Evgeni Burovski

X = np.asarray([[1.0, 0.0, 3.0, 8.0],
                [2.0, 0.0, 1.0, 1.0],
                [1.5, 2.5, 1.0, 0.0]])
n = 4
M = np.logical_and.reduce(np.mod(X, 1) == 0, axis=-1)
M &= (X.sum(axis=-1) == n)
print(X[M])

100. 1 次元配列 X の平均値に対し、ブートストラップによる 95% 信頼区間を計算してください(配列の要素を復元抽出で N 回サンプリングし、各サンプルの平均を計算し、その平均のパーセンタイルを取る)★★★

ヒント

np.percentile

解答
# Author: Jessica B. Hamrick

X = np.random.randn(100)  # ランダムな 1 次元配列
N = 1000  # ブートストラップサンプル数
idx = np.random.randint(0, X.size, (N, X.size))
means = X[idx].mean(axis=1)
confint = np.percentile(means, [2.5, 97.5])
print(confint)

以上で 100 問の NumPy 練習問題の日本語訳は完了です。お疲れさまでした!

さらに pandas の練習問題に取り組みたい場合は、100 pandas 練習問題 をご覧ください。