numpy-100 日本語翻訳 (61-80)

numpy100 を翻訳したので100 numpy exercises (日本語翻訳版)、ブログにしました


61. 与えられた値から最も近い値を配列の中に見つける (★★☆)

 

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

 

62. shape属性が (1,3) と (3,1) の2つの配列があるとき、イテレータを使ってその和を計算する方法は? (★★☆)

 

答え
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])
[[0 1 2]
 [1 2 3]
 [2 3 4]]

 

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.info = getattr(obj, 'name', "no name")
Z = NamedArray(np.arange(10), "range_10")
print (Z.name)
range_10

 

64. あるベクトルが与えられたとき、第2のベクトルにより添え字指定されたそれぞれの要素に 1 を加える方法は (添え字は繰り返されることに注意)? (★★★)

 

答え
# Author: Brett Olsen
Z = np.ones(10)
I = np.random.randint(0,len(Z),20)
Z += np.bincount(I, minlength=len(Z))
print(Z)
# Another solution
# Author: Bartosz Telenczuk
np.add.at(Z, I, 1)
print(Z)
[2. 3. 2. 3. 3. 4. 2. 2. 1. 8.]
[ 3.  5.  3.  5.  5.  7.  3.  3.  1. 15.]

 

65. 添え字リスト (I) に基づきベクトル (X) の要素を配列 (F) に累積する方法は? (★★★)

 

答え
# 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)
[0. 7. 0. 6. 5. 0. 0. 0. 0. 3.]

 

66. 画像が (w, h, 3) (dtype=ubyte) のとき、ユニークな色の数を計算する(★★★)

 

答え
# Author: Nadav Horesh
w,h = 16,16
I = np.random.randint(0,2,(h,w,3)).astype(np.ubyte)
F = I[...,0]*256*256 + I[...,1]*256 +I[...,2]
n = len(np.unique(F))
print(np.unique(I))
[0 1]

 

67. 4次元配列のとき、一気に最後の2軸で合計する方法は? (★★★)

 

答え
A = np.random.randint(0,10,(3,4,3,4))
# solution by passing a tuple of axes (introduced in numpy 1.7.0)
sum = A.sum(axis=(-2,-1))
print(sum)
# solution by flattening the last two dimensions into one
# (useful for functions that don't accept tuples for axis argument)
sum = A.reshape(A.shape[:-2] + (-1,)).sum(axis=-1)
print(sum)
[[48 56 68 41]
 [71 54 49 66]
 [55 42 35 55]]
[[48 56 68 41]
 [71 54 49 66]
 [55 42 35 55]]

 

68. 1次元ベクトル D を考えたとき、部分集合を添え字で記述する同じサイズのベクトル S を使用して、D の部分集合の平均を計算する方法は?

 

答え
# 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 solution as a reference due to more intuitive code
import pandas as pd
print(pd.Series(D).groupby(S).mean())
[0.60751631 0.68402626 0.43938439 0.51212031 0.45235217 0.50947915
 0.52321953 0.29345941 0.56430143 0.43939577]
0    0.607516
1    0.684026
2    0.439384
3    0.512120
4    0.452352
5    0.509479
6    0.523220
7    0.293459
8    0.564301
9    0.439396
dtype: float64

 

69. ドット積の対角要素を取得する方法は? (★★★)

 

答え
# Author: Mathieu Blondel
A = np.random.uniform(0,1,(5,5))
B = np.random.uniform(0,1,(5,5))
# Slow version  
np.diag(np.dot(A, B))
# Fast version
np.sum(A * B.T, axis=1)
# Faster version
np.einsum("ij,ji->i", A, B)
array([1.92289093, 1.09022359, 0.80127718, 0.80379736, 1.05785065])

 

70. ベクトル \[1, 2, 3, 4, 5\] があるとき、それぞれの値の間に連続する3つのゼロをはさむ新しいベクトルを生成する方法は? (★★★)

 

答え
# 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)
[1. 0. 0. 0. 2. 0. 0. 0. 3. 0. 0. 0. 4. 0. 0. 0. 5.]

 

71. (5,5,3) 次元の配列があるとき、それに (5,5) 次元の配列を掛ける方法は? (★★★)

 

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

 [[2. 2. 2.]
  [2. 2. 2.]
  [2. 2. 2.]
  [2. 2. 2.]
  [2. 2. 2.]]

 [[2. 2. 2.]
  [2. 2. 2.]
  [2. 2. 2.]
  [2. 2. 2.]
  [2. 2. 2.]]

 [[2. 2. 2.]
  [2. 2. 2.]
  [2. 2. 2.]
  [2. 2. 2.]
  [2. 2. 2.]]

 [[2. 2. 2.]
  [2. 2. 2.]
  [2. 2. 2.]
  [2. 2. 2.]
  [2. 2. 2.]]]

 

72. 配列の2つの行を交換する方法は? (★★★)

 

答え
# Author: Eelco Hoogendoorn
A = np.arange(25).reshape(5,5)
A0,1 = A1,0
print(A)
[[ 5  6  7  8  9]
 [ 0  1  2  3  4]
 [10 11 12 13 14]
 [15 16 17 18 19]
 [20 21 22 23 24]]

 

73. 10個の三角形を記述する10個の三つ組みがあるとき (共有された頂点を持つ) 、すべての三角形を構成するユニークな線分の集合を見つける (★★★)

 

答え
# 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)
[( 8, 47) ( 8, 92) (11, 50) (11, 61) (14, 14) (14, 98) (17, 48) (17, 76)
 (18, 61) (18, 75) (21, 36) (21, 71) (24, 78) (24, 91) (34, 53) (34, 86)
 (36, 71) (44, 78) (44, 84) (47, 92) (48, 76) (50, 61) (53, 86) (61, 75)
 (67, 76) (67, 79) (76, 79) (78, 84) (78, 91)]

 

74. bincountで与えられる配列 C があるとき、np.bincount(A) == C であるような配列 A の生成方法は? (★★★)

 

答え
# 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)
[1 1 2 3 4 4 6]

 

75. 配列にスライドウィンドウを使って平均を計算する方法は? (★★★)

 

答え
# 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))
[ 1.  2.  3.  4.  5.  6.  7.  8.  9. 10. 11. 12. 13. 14. 15. 16. 17. 18.]

 

76. 1次元の配列 Z があるとき、最初の行が (Z\[0\],Z\[1\],Z\[2\]) で、それに続く行はそれぞれ 1 だけシフトされた2次元配列を生成する (最後の行は、(Z\[-3\],Z\[-2\],Z\[-1\]) になる) (★★★)

 

答え
# Author: Joe Kington / Erik Rigtorp
from numpy.lib import stride_tricks
def rolling(a, window):
   shape = (a.size - window + 1, window)
   strides = (a.itemsize, a.itemsize)
   return stride_tricks.as_strided(a, shape=shape, strides=strides)
Z = rolling(np.arange(10), 3)
print(Z)
[[0 1 2]
 [1 2 3]
 [2 3 4]
 [3 4 5]
 [4 5 6]
 [5 6 7]
 [6 7 8]
 [7 8 9]]

 

77. ブール値を否定する方法、また、浮動小数点の符号を変更する方法は? (★★★)

 

答え
# 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)
array([ 6.66898337e-01, -6.98527739e-04,  9.20447662e-02, -5.73084574e-02,
       -6.53843844e-02, -9.91554888e-01, -9.13247565e-01, -3.97117480e-01,
       -2.39728156e-01, -8.17936435e-01, -7.16220887e-01, -4.50298191e-01,
       -3.87611399e-01,  1.93408286e-01,  2.57558774e-01, -2.65953798e-01,
       -3.53615965e-01,  1.08129061e-02,  8.79310991e-01, -4.05659194e-01,
        2.88015696e-01, -5.07333423e-01, -3.07480683e-02,  6.62792058e-01,
        6.40187694e-01, -9.84522055e-01,  5.67391835e-01, -4.99376218e-01,
       -6.19606963e-01, -4.01239902e-01,  3.62533032e-01, -7.20593105e-01,
        1.05007658e-01,  9.37454411e-01,  9.56880248e-01, -6.87804748e-01,
        1.22142154e-02,  3.59736011e-02, -1.59751748e-01, -4.09656167e-01,
        3.28994958e-01,  8.46701615e-01,  4.18183319e-01,  8.11740559e-01,
       -5.74192505e-01,  3.07455282e-01, -8.56346769e-01,  1.75783012e-01,
       -3.29576220e-01,  2.11181297e-01,  3.10209125e-01,  8.93834215e-01,
       -6.96852422e-01,  3.89852980e-01,  8.04869146e-01,  4.80201513e-01,
        5.60469139e-01, -2.70319847e-01,  8.01106341e-01,  7.11306274e-01,
        5.40219612e-01, -5.44787360e-01,  4.80961559e-01, -1.62117647e-01,
       -3.88579077e-01,  8.97179975e-01, -2.39643365e-01,  6.39871872e-01,
        3.48702200e-01,  6.86647145e-01,  2.25676066e-01,  5.93469341e-02,
       -3.63841598e-01,  9.00214436e-01,  2.67690114e-01, -5.13486996e-01,
       -2.51272595e-01, -6.91807367e-02, -9.04999894e-01, -8.64407656e-02,
       -9.06695725e-01,  6.72690131e-01, -9.74125086e-01, -7.81823233e-01,
       -8.86791167e-01,  9.11039945e-01,  1.88707089e-01, -1.78731880e-01,
       -3.09510067e-02,  7.96961668e-01,  6.71530888e-01, -6.46892404e-01,
       -7.30535643e-01,  4.05945868e-01, -5.43933229e-01,  2.33200937e-01,
       -6.84542747e-01, -6.58881534e-01,  9.18060795e-01, -8.66962555e-01])

 

78. 直線 (2次元) を記述する2組の点 P0、P1そして点 p があるとき、点 p から直線 i (P0\[i\],P1\[i\]) までの距離を計算する方法は? (★★★)

 

答え
def distance(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))
P0 = np.random.uniform(-10,10,(10,2))
P1 = np.random.uniform(-10,10,(10,2))
p  = np.random.uniform(-10,10,( 1,2))
print(distance(P0, P1, p))
[ 0.7226039   1.74754301  3.9490312   1.42006718  5.44462552  1.15105765
  3.42139445 10.15384561  2.61928783  4.91884265]

 

79. 直線 (2次元) を記述する2組の点 P0、P1 そして1組の点 P があるとき、それぞれの点 (P\[j\]) から各線 i (P0\[i\],P1\[i\]) までの距離を計算する方法は? (★★★)

 

答え
# Author: Italmassov Kuanysh
# based on distance function from previous question
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]))
[[9.98756271e+00 2.34704447e+00 9.97834806e-02 2.57026169e+00
  5.04216551e+00 3.91132449e+00 7.18967689e+00 6.02350716e+00
  1.05165640e+00 3.68076127e+00]
 [1.83277951e+01 8.78620184e-02 6.79192484e+00 2.48600068e+00
  1.16547097e+01 4.38650385e-01 1.55870665e+01 1.34332685e+01
  7.10214556e+00 1.09984504e+01]
 [7.04576863e-03 1.08440837e+01 4.20935929e+00 3.22858524e+00
  1.52264075e+00 2.11280475e+00 2.14734189e+00 7.11347051e-01
  8.62907352e+00 7.50194529e+00]
 [1.03580725e+01 2.45984233e+00 3.16653178e+00 6.73608883e+00
  1.75530750e+00 8.60202639e+00 6.97248436e+00 3.45269953e+00
  2.47277467e+00 5.96778238e+00]
 [1.78814722e+00 1.46284952e+01 3.34615542e-01 1.84363281e+00
  6.19500070e+00 3.03098868e+00 1.95737750e-01 4.93769777e+00
  5.25580460e+00 7.70710690e+00]
 [1.76140340e+01 2.41584465e-01 5.82747522e+00 1.56560370e+00
  1.06910794e+01 1.27401054e+00 1.48028514e+01 1.24770151e+01
  6.20624979e+00 1.05901258e+01]
 [1.61500892e+00 4.71978411e-01 1.06637460e+01 1.23914551e+01
  5.46604846e+00 1.26340574e+01 1.87820747e+00 4.54936210e+00
  1.11645543e+01 1.54476255e+00]
 [3.23456564e+00 5.21794419e+00 4.93342259e+00 5.69255437e+00
  4.80533239e-01 5.65080569e+00 5.21034449e-01 6.65736349e-01
  7.25900656e+00 2.67851598e+00]
 [1.76621308e+01 7.38610617e+00 1.13429040e+01 8.72235461e+00
  1.65420981e+01 6.61149793e+00 1.58094945e+01 1.72276677e+01
  9.14841151e+00 7.44725533e+00]
 [9.54322480e+00 1.14113904e-01 2.15342470e+00 5.03489344e+00
  2.89954185e+00 6.51885356e+00 6.44716933e+00 4.17873216e+00
  2.37774627e+00 4.27188182e+00]]

 

80. 任意の配列に対して、定められたshape属性で、指定された要素が中央に配置されるような一部分を抽出する関数を書く(必要に応じて `fill` 値でパディング) (★★★)

 

答え
# 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 = [slice(start,stop) for start,stop in zip(R_start,R_stop)]
z = [slice(start,stop) for start,stop in zip(Z_start,Z_stop)]
R[r] = Z[z]
print(Z)
print(R)
[[1 7 3 6 6 4 9 4 8 4]
 [7 1 1 7 0 0 1 1 1 5]
 [3 2 6 4 8 8 9 9 0 4]
 [7 0 3 8 9 8 4 4 2 6]
 [8 3 4 1 9 9 0 0 1 9]
 [7 8 4 4 2 7 8 8 4 0]
 [2 1 7 6 2 9 4 5 0 3]
 [5 1 0 4 2 0 5 6 4 4]
 [9 4 4 2 4 8 4 3 8 9]
 [8 4 2 6 6 0 0 8 8 1]]
[[0 0 0 0 0]
 [0 1 7 3 6]
 [0 7 1 1 7]
 [0 3 2 6 4]
 [0 7 0 3 8]]