Python 什么';这是将函数应用于numpy数组的行/列维度的最佳方法

Python 什么';这是将函数应用于numpy数组的行/列维度的最佳方法,python,numpy,Python,Numpy,我有一个三维numpy数组。直观地说,它是二维的,其中每一行的列位置代表一个RGB颜色,它存储为三个数字的向量。(如果将颜色存储为三元组,会容易得多!)我有一个函数(基于答案)可以将RGB三元组转换为颜色名称。是否有一种简单的方法(除了嵌套循环)将该函数应用于数组的行-列元素。(直接将其应用于数组本身不起作用,因为numpy尝试将该函数应用于RGB向量的每个元素。) 谢谢。IIUC,您可以使用np.dstack和重塑,或者np.dstack和串联 np.dstack(arr).reshape(-

我有一个三维numpy数组。直观地说,它是二维的,其中每一行的列位置代表一个RGB颜色,它存储为三个数字的向量。(如果将颜色存储为三元组,会容易得多!)我有一个函数(基于答案)可以将RGB三元组转换为颜色名称。是否有一种简单的方法(除了嵌套循环)将该函数应用于数组的行-列元素。(直接将其应用于数组本身不起作用,因为numpy尝试将该函数应用于RGB向量的每个元素。)


谢谢。

IIUC,您可以使用
np.dstack
重塑
,或者
np.dstack
串联

np.dstack(arr).reshape(-1,3)
# equivalent:
np.concatenate(np.dstack(arr))
例如:

arr = np.random.randint(0,256,(3,5,5))
>>> arr
array([[[150,  38,  34,  41,  24],
        [ 76, 135,  93, 149, 142],
        [150, 123, 198,  11,  34],
        [ 24, 179, 132, 175, 218],
        [ 46, 233, 138, 215,  97]],

       [[194, 153,  29, 200, 133],
        [247, 101,  18,  70, 112],
        [164, 225, 141, 196, 131],
        [ 15,  86,  22, 234, 166],
        [163,  97,  94, 205,  56]],

       [[117,  56,  28,   1, 104],
        [138, 138, 148, 241,  44],
        [ 73,  57, 179, 142, 140],
        [ 55, 160, 240, 189,  13],
        [244,  36,  56, 241,  33]]])

>>> np.dstack(arr).reshape(-1,3)
array([[150, 194, 117],
       [ 38, 153,  56],
       [ 34,  29,  28],
       [ 41, 200,   1],
       [ 24, 133, 104],
       [ 76, 247, 138],
       [135, 101, 138],
       [ 93,  18, 148],
       [149,  70, 241],
       [142, 112,  44],
       [150, 164,  73],
       [123, 225,  57],
       [198, 141, 179],
       [ 11, 196, 142],
       [ 34, 131, 140],
       [ 24,  15,  55],
       [179,  86, 160],
       [132,  22, 240],
       [175, 234, 189],
       [218, 166,  13],
       [ 46, 163, 244],
       [233,  97,  36],
       [138,  94,  56],
       [215, 205, 241],
       [ 97,  56,  33]])
使用中提供的功能,可以获得该图像最接近的颜色:

>>> [get_colour_name(i)[1] for i in np.dstack(arr).reshape(-1,3)]
['darkseagreen', 'forestgreen', 'black', 'limegreen', 'seagreen', 'mediumaquamarine', 'grey', 'indigo', 'blueviolet', 'sienna', 'yellowgreen', 'yellowgreen', 'rosybrown', 'lightseagreen', 'darkcyan', 'midnightblue', 'palevioletred', 'blueviolet', 'powderblue', 'goldenrod', 'dodgerblue', 'chocolate', 'sienna', 'gainsboro', 'saddlebrown']

IIUC,您可以使用
np.dstack
重塑
,或
np.dstack
串联

np.dstack(arr).reshape(-1,3)
# equivalent:
np.concatenate(np.dstack(arr))
例如:

arr = np.random.randint(0,256,(3,5,5))
>>> arr
array([[[150,  38,  34,  41,  24],
        [ 76, 135,  93, 149, 142],
        [150, 123, 198,  11,  34],
        [ 24, 179, 132, 175, 218],
        [ 46, 233, 138, 215,  97]],

       [[194, 153,  29, 200, 133],
        [247, 101,  18,  70, 112],
        [164, 225, 141, 196, 131],
        [ 15,  86,  22, 234, 166],
        [163,  97,  94, 205,  56]],

       [[117,  56,  28,   1, 104],
        [138, 138, 148, 241,  44],
        [ 73,  57, 179, 142, 140],
        [ 55, 160, 240, 189,  13],
        [244,  36,  56, 241,  33]]])

>>> np.dstack(arr).reshape(-1,3)
array([[150, 194, 117],
       [ 38, 153,  56],
       [ 34,  29,  28],
       [ 41, 200,   1],
       [ 24, 133, 104],
       [ 76, 247, 138],
       [135, 101, 138],
       [ 93,  18, 148],
       [149,  70, 241],
       [142, 112,  44],
       [150, 164,  73],
       [123, 225,  57],
       [198, 141, 179],
       [ 11, 196, 142],
       [ 34, 131, 140],
       [ 24,  15,  55],
       [179,  86, 160],
       [132,  22, 240],
       [175, 234, 189],
       [218, 166,  13],
       [ 46, 163, 244],
       [233,  97,  36],
       [138,  94,  56],
       [215, 205, 241],
       [ 97,  56,  33]])
使用中提供的功能,可以获得该图像最接近的颜色:

>>> [get_colour_name(i)[1] for i in np.dstack(arr).reshape(-1,3)]
['darkseagreen', 'forestgreen', 'black', 'limegreen', 'seagreen', 'mediumaquamarine', 'grey', 'indigo', 'blueviolet', 'sienna', 'yellowgreen', 'yellowgreen', 'rosybrown', 'lightseagreen', 'darkcyan', 'midnightblue', 'palevioletred', 'blueviolet', 'powderblue', 'goldenrod', 'dodgerblue', 'chocolate', 'sienna', 'gainsboro', 'saddlebrown']

您可以使用
map
并尝试,例如:

list(map(your_RGB2Name_function, 2D_np_array))
假设您有一个函数,它可以处理数字列表

def dummy_fct(numlist):
    return '-'.join(map(str, numlist))

dummy_fct([1,2,3])
Out: '1-2-3'
当应用于许多数字列表时,它显然不起作用

dummy_fct([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
Out: '[1, 2, 3]-[4, 5, 6]-[7, 8, 9]'
然后,您可以使用
map
,它迭代一个iterable(此处的外部列表,或者在您的情况下,是numpy数组的第二个维度),并在每个子列表上应用该函数:

list(map(dummy_fct, [[1, 2, 3], [4, 5, 6], [7, 8, 9]]))
Out: ['1-2-3', '4-5-6', '7-8-9']

您可以使用
map
并尝试,例如:

list(map(your_RGB2Name_function, 2D_np_array))
假设您有一个函数,它可以处理数字列表

def dummy_fct(numlist):
    return '-'.join(map(str, numlist))

dummy_fct([1,2,3])
Out: '1-2-3'
当应用于许多数字列表时,它显然不起作用

dummy_fct([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
Out: '[1, 2, 3]-[4, 5, 6]-[7, 8, 9]'
然后,您可以使用
map
,它迭代一个iterable(此处的外部列表,或者在您的情况下,是numpy数组的第二个维度),并在每个子列表上应用该函数:

list(map(dummy_fct, [[1, 2, 3], [4, 5, 6], [7, 8, 9]]))
Out: ['1-2-3', '4-5-6', '7-8-9']

如果你的函数不是为接受向量参数而设计的,那么除了使用循环并简单地隐藏它们或者一些jit恶作剧之外,就没有什么魔力了,但我不是后者的专家

这就是秘密应用循环的魔力,那就是
np.vectorize
。要使其向函数传递1D子空间,可以使用
签名
关键字

pseudo_vect_func = np.vectorize(your_func, ('O',), signature='(m)->()')
我还添加了一个otypes参数,因为如果没有它,vectorize似乎会盲目地选择
U1
,即在第一个字母后截断

如果您想要真正的矢量化操作,这里有一个从头开始的方法

如果您有一个带有(颜色名称,(r,g,b))值的列表或字典,并且可以进行最小距离匹配,则可以利用KDTrees进行高效查找:

import numpy as np
from scipy.spatial import cKDTree as KDTree

# set up lookup

# borrow a list of named colors from matplotlib
from matplotlib import colors
named_colors = {k: tuple(int(v[i:i+2], 16) for i in range(1, 7, 2))
                for k, v in colors.cnames.items()}

no_match = named_colors['purple']

# make arrays containing the RGB values ...
color_tuples = list(named_colors.values())
color_tuples.append(no_match)
color_tuples = np.array(color_tuples)
# ... and another array with the names in same order
color_names = list(named_colors)
color_names.append('no match')
color_names = np.array(color_names)
# build tree
tree = KDTree(color_tuples[:-1])

def img2colornames(img, tolerance):
    # find closest color in tree for each pixel in picture
    dist, idx = tree.query(img, distance_upper_bound=tolerance)
    # look up their names
    return color_names[idx]

# an example
result = img2colornames(face(), 40)
# show a small patch
import Image
Image.fromarray(face()[410:510, 325:425]).show()
# same as names, downsampled
print(result[415:510:10, 330:425:10])
输出:


如果你的函数不是为接受向量参数而设计的,那么除了使用循环并简单地隐藏它们或者一些jit恶作剧之外,就没有什么魔力了,但我不是后者的专家

这就是秘密应用循环的魔力,那就是
np.vectorize
。要使其向函数传递1D子空间,可以使用
签名
关键字

pseudo_vect_func = np.vectorize(your_func, ('O',), signature='(m)->()')
我还添加了一个otypes参数,因为如果没有它,vectorize似乎会盲目地选择
U1
,即在第一个字母后截断

如果您想要真正的矢量化操作,这里有一个从头开始的方法

如果您有一个带有(颜色名称,(r,g,b))值的列表或字典,并且可以进行最小距离匹配,则可以利用KDTrees进行高效查找:

import numpy as np
from scipy.spatial import cKDTree as KDTree

# set up lookup

# borrow a list of named colors from matplotlib
from matplotlib import colors
named_colors = {k: tuple(int(v[i:i+2], 16) for i in range(1, 7, 2))
                for k, v in colors.cnames.items()}

no_match = named_colors['purple']

# make arrays containing the RGB values ...
color_tuples = list(named_colors.values())
color_tuples.append(no_match)
color_tuples = np.array(color_tuples)
# ... and another array with the names in same order
color_names = list(named_colors)
color_names.append('no match')
color_names = np.array(color_names)
# build tree
tree = KDTree(color_tuples[:-1])

def img2colornames(img, tolerance):
    # find closest color in tree for each pixel in picture
    dist, idx = tree.query(img, distance_upper_bound=tolerance)
    # look up their names
    return color_names[idx]

# an example
result = img2colornames(face(), 40)
# show a small patch
import Image
Image.fromarray(face()[410:510, 325:425]).show()
# same as names, downsampled
print(result[415:510:10, 330:425:10])
输出:


类似:一种方法是
np.vectorize
。那么您想要一个2d字符串数组-颜色名称?如果您展示该功能,并演示如何在小型3d阵列上使用它,您将获得最大的帮助(循环可以)。存储为三元组的
是什么意思?什么的三倍。如果你的数组是(n,m,3)形的,那么
arr[i,j,:]
是一个点的“三元组”,不是吗?类似的:一种方法是
np.vectorize
。所以你想要一个二维字符串数组-颜色名称?如果您展示该功能,并演示如何在小型3d阵列上使用它,您将获得最大的帮助(循环可以)。存储为三元组的
是什么意思?什么的三倍。如果你的数组是(n,m,3)形的,那么
arr[i,j,:]
是一个点的“三元组”,不是吗?谢谢。这本质上与列表理解或嵌套循环相同。我希望能有一些小魔术,能把上面的两个维度撇掉。你说的
撇掉上面的两个维度是什么意思?如果您的函数一次只能处理一个点的3个值,则必须以一种或另一种方式为每个点调用该函数一次?我建议您发布您选择的函数或一个伪函数,它接受完全相同的输入参数并返回完全相同类型的结果值。另外,请发布一个数据的样本数组,我们希望在其上应用函数,这样我们就可以用努力解决问题,而不是猜测您的帧条件。谢谢。这本质上与列表理解或嵌套循环相同。我希望能有一些小魔术,能把上面的两个维度撇掉。你说的
撇掉上面的两个维度是什么意思?如果您的函数一次只能处理一个点的3个值,则必须以一种或另一种方式为每个点调用该函数一次?我建议您发布您选择的函数或一个伪函数,它接受完全相同的输入参数并返回完全相同类型的结果值。另外,请发布一个数据的样本数组,我们希望在其上应用函数,这样我们就可以用努力解决问题,而不是猜测您的帧条件。谢谢。听起来很有希望。我想保持原形,还有essentia