意外と詰まったし良いまとめがないので書く.
1 一番近い値の重複を考えない場合
1.1 最もシンプルなバージョン
探したい値が一つで,返したい index も一つの場合.これが最も簡単.探索されるデータは1次元配列を想定.
import numpy as np def idx_of_the_nearest(data, value): idx = np.argmin(np.abs(np.array(data) - value)) return idx
1.2 具体例
data = [1, 1 ,1 ,0.5 ,2 ,3 ,-1] value = 0.8 n = idx_of_the_nearest(data, value) n #0
1.3 探したい値が複数ある場合
探したい値をリストで指定できるようにしたい.そのための関数が以下.
import numpy as np def idx_of_the_nearest(data, value): print('value:', type(value)) if type(value) == float: idx = np.argmin(np.abs(np.array(data) - value)) #print(np.abs(np.array(data) - value)) return idx if type(value) == list: idx = [None]*len(value) for i in range(len(value)): idx[i] = np.argmin(np.abs(np.array(data) - value[i])) #idx[i] = [value[i], np.argmin(np.abs(np.array(data) - value[i]))] #としてもよい #print(np.abs(np.array(data) - value[i])) return idx
1.4 具体例
data = [1, 1 ,1 ,0.5 ,2 ,3 ,-1] value = [0.8,0.7] n = idx_of_the_nearest(data, value) n '''Result value: <class 'list'> [0, 3] '''
1.5 多次元に拡張
探索される対象のデータが多次元配列の場合に,多次元配列の index を返したい人はこちら.出力はタプルのリスト.np.unravel_index()
なるものを使う.
import numpy as np def idx_of_the_nearest(data, value): print('value:', type(value)) if type(value) == float: idx = np.argmin(np.abs(np.array(data) - value)) #print(np.abs(np.array(data) - value)) return idx if type(value) == list: idx = [None]*len(value) for i in range(len(value)): idx[i] = np.unravel_index(np.argmin(np.abs(np.array(data) - value[i])) , np.array(data).shape) #print(np.abs(np.array(data) - value[i])) return idx
1.6 具体例
data = [[1, 1 ,1 ,0.5] ,[2 ,3 ,-1,0]] value = [0.8, 0.7, 2] idx_of_the_nearest(data, value) ''' value: <class 'list'> [(0, 0), (0, 3), (1, 0)] '''
2 最も近い値が複数ある場合
最もなのに「複数」とはどういうことだ,とは言わないでいただきたい.そういうことも数学ではままあるのである(今までもそういう具体例をわざと作っておいた.).
2.1 シンプルなバージョン
最もシンプルに添字を複数返したい方はこちら.1次元配列で探したい値が1つだけある場合.
import numpy as np def indices_of_the_nearest(data, value): distance = np.abs(np.array(data) - value) indices = np.where(distance == np.min(distance))[0] return indices
この np.where()
なるものが曲者で,意外と使いにくい.
ただ,シンプルなバージョンでは,具体例で見るようにこれが最適解である.[0]
をつけることで array
が返ってくる.
2.2 具体例
data = [1, 1 ,1 ,0.5 ,2 ,3 ,-1] value = 0.8 indices_of_the_nearest(data, value) ''' array([0, 1, 2]) '''
2.3 探したい値が複数ある場合(多次元でも使えるが改良の余地あり)
探す値も複数にしたいという「欲張り」な人はこちら.ただし改良の余地がある.
import numpy as np def indices_of_the_nearest(data, value): print('value:', type(value)) if type(value) == float: distance = np.abs(np.array(data) - value) indices = np.where(distance == np.min(distance)) #print(np.abs(np.array(data) - value)) return indices if type(value) == list: indices = [None]*len(value) for i in range(len(value)): distance = np.abs(np.array(data) - value[i]) indices[i] = np.where(distance == np.min(distance)) #print(np.abs(np.array(data) - value[i])) return indices
1.3 節を応用しただけ.
2.4 具体例
data = [[1, 1 ,1 ,0.5] ,[2 ,3 ,-1,0]] value = [0.8,0.7] indices_of_the_nearest(data, value) ''' value: <class 'list'> [(array([0, 0, 0]), array([0, 1, 2])), (array([0]), array([3]))] '''
行番号と列番号が分離して出力されてわかりにくい(1つ目の要素の意味は[0][0]と[0][1]と[0][2]に一番近い値がありますよ,という意味).
どうしてもという人はこれを使えばよいが,今回の目的からしてあまり使う意味もない.data が1次元の場合は問題なかったのだが,これが更に3次元となってくるともっと見にくい.
data = [[[1, 1] ,[1 ,0.5]] ,[[2 ,3] ,[-1,0]]] value = [0.8,0.7] indices_of_the_nearest(data, value) ''' value: <class 'list'> [(array([0, 0, 0]), array([0, 0, 1]), array([0, 1, 0])), (array([0]), array([1]), array([1]))] '''
リストの中の1つ目のタプルは[0][0][0], [0][0][1], [0][1][0]
に一番近い値がありますよという意味.
これは array の中をそのまま読んでいるのでなくて,array([0, 0, 0])
の i (i = 0, 1, 2, 3) 番目とarray([0, 0, 1])
の i 番目とarray([0, 1, 0])
の i 番目をつなげて読んでいる(リストの中の2つ目のタプルを合わせて見れば意味がわかる).
見にくい!
2.5 多次元に拡張(改良版)
というわけで改良しよう.
import numpy as np def indices_of_the_nearest(data, value): print('value:', type(value)) if type(value) == float: distance = np.abs(np.array(data) - value) indices = np.where(distance == np.min(distance)) #print(np.abs(np.array(data) - value)) return indices if type(value) == list: indices = [None]*len(value) for i in range(len(value)): distance = np.abs(np.array(data) - value[i]) indices[i] = np.array((np.where(distance == np.min(distance)))).T #Transpose #print(np.abs(np.array(data) - value[i])) return indices
何をやっているかというと,
indices[i] = np.array((np.where(distance == np.min(distance)))).T
と書き換えただけ.
2.6 具体例
data = [[1, 1 ,1 ,0.5] ,[2 ,3 ,-1,0]] value = [0.8,0.7] indices_of_the_nearest(data, value) ''' value: <class 'list'> [array([[0, 0], [0, 1], [0, 2]]), array([[0, 3]])] '''
data = [[[1, 1] ,[1 ,0.5]] ,[[2 ,3] ,[-1,0]]] value = [0.8,0.7] indices_of_the_nearest(data, value) ''' value: <class 'list'> [array([[0, 0, 0], [0, 0, 1], [0, 1, 0]]), array([[0, 1, 1]])] '''
見やすい!(出力から要素を取り出したい場合は 内包表記で for 文を回すなどすればできると思う)
3 まとめ
添字取り出し,意外と大変だったけど,いつかどこかの誰かの役に立てれば.