假設我有以下 numpy 陣列,僅包含 1 和 0:
import numpy as np
example = np.array([0,1,1,0,1,0,0,1,1], dtype=np.uint8)
我想將所有元素分組為3的塊,并根據條件將這些塊替換為單個值。假設我希望[0,1,1]變為5,并且[0,1,0]變為10。因此,所需的輸出將是:
[5,10,5]
一個塊中所有可能的 1 和 0 組合都有一個對應的唯一值,應該替換該塊。最快的方法是什么?
uj5u.com熱心網友回復:
我建議您將陣列重塑為 3 by something 陣列。現在我們可以將每一行視為一個二進制數,它是您想要的值串列的索引。您將其轉換為該數字并索引到值中。
arr = np.array([0,1,1,0,1,0,0,1,1], dtype=np.uint8).reshape(-1,3)
idx = 2**0*arr[:,0] 2**1*arr[:,1] 2**2*arr[:,2]
values = np.zeros(2**3)
values[0 *2**0 1 *2**1 1 *2**2] = 5
values[0 *2**0 1 *2**1 0 *2**2] = 10
values[idx]
這給了
array([ 5., 10., 5.])
或者,如果您希望更簡潔地撰寫轉換,盡管有點不那么基本(感謝@mozway 的想法):
def bin_vect_to_int(arr):
bin_units = 2**np.arange(arr.shape[1])
return np.dot(arr,bin_units)
arr = np.array([0,1,1,0,1,0,0,1,1,0,1,1], dtype=np.uint8).reshape(-1,3)
idx = binVecToInt(arr)
values = np.zeros(2**3)
values[bin_vect_to_int(np.array([[0,1,1]]))] = 5
values[bin_vect_to_int(np.array([[0,1,0]]))] = 10
values[idx]
uj5u.com熱心網友回復:
您可以使用 的連續陣列視圖shape(3, -1),查找唯一出現的位置并在這些位置替換它們:
def view_ascontiguous(a): # a is array
a = np.ascontiguousarray(a)
void_dt = np.dtype((np.void, a.dtype.itemsize * a.shape[1]))
return a.view(void_dt).ravel()
def replace(x, args, subs, viewer):
u, inv = np.unique(viewer(x), return_inverse=True)
idx = np.searchsorted(viewer(args), u)
return subs[idx][inv]
>>> replace(x=np.array([1, 0, 1, 0, 0, 1, 1, 0, 1]).reshape(-1, 3),
args=np.array([[0, 0, 0], [0, 0, 1], [0, 1, 0], [0, 1, 1], [1, 0, 0], [1, 0, 1], [1, 1, 0], [1, 1, 1]]),
subs=np.array([ 5, 57, 58, 44, 67, 17, 77, 1]),
viewer=view_ascontiguous)
array([17, 57, 17])
現在,有趣的部分:您可以使用自己的viewer. 需要將傳入的陣列映射args到任何型別的升序索引,如下所示:
viewer=lambda arr: np.ravel_multi_index(arr.T, (2,2,2)) #0, 1, 2, 3, 4, 5, 6, 7
viewer=lambda arr: np.sum(arr * [4, 2, 1], axis=1) #0, 1, 2, 3, 4, 5, 6, 7
viewer=lambda arr: np.dot(arr, [4, 2, 1]) #0, 1, 2, 3, 4, 5, 6, 7
或者更有趣:
viewer=lambda arr: 2*np.dot(arr, [4, 2, 1]) 1 #1, 3, 5, 7, 9, 11, 13, 15
viewer=lambda arr: np.vectorize(chr)(97 np.dot(arr, [4, 2, 1])) #a b c d e f g h
因為你也可以映射
[[0, 0, 0], [0, 0, 1], [0, 1, 0], [0, 1, 1], [1, 0, 0], [1, 0, 1], [1, 1, 0], [1, 1, 1]]
到任何你能想到的升序[1, 3, 5, 7, 9, 11, 13, 15]或['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h']
,結果保持不變。
uj5u.com熱心網友回復:
正如其他答案所示,您可以從重塑您的陣列開始(實際上,您可能應該以正確的形狀開始生成它,但這是另一個問題):
example = np.array([0, 1, 1, 0, 1, 0, 0, 1, 1], dtype=np.uint8)
data = example.reshape(-1, 3)
現在在陣列上運行自定義 python 函式會很慢,但幸運的是 numpy 有你的支持。您可以使用np.packbits將每一行直接轉換為一個數字:
data = np.packbits(data, axis=1, bitorder='little').ravel() # [6, 2, 6]
如果你想101映射到5和110映射到6,你的作業就完成了。否則,您將需要提出一個映射。由于您有三位,因此映射陣列中只需要 8 個數字:
mapping = np.array([7, 4, 3, 8, 124, 1, 5, 0])
您可以data直接將其用作索引mapping。輸出的型別為 ,mapping但形狀為data:
result = mapping[data] # [5, 3, 5]
您可以在一行中執行此操作:
mapping[np.packbits(example.reshape(-1, 3), axis=1, bitorder='little').ravel()]
轉載請註明出處,本文鏈接:https://www.uj5u.com/qukuanlian/416470.html
標籤:
上一篇:在python中生成大小為1000的0到50的亂數的干凈方法,沒有相似的出現次數
下一篇:加快點積乘法的Cython實作
