标签归档:multidimensional-array

在Python中旋转二维数组

问题:在Python中旋转二维数组

在一个程序中,我正在编写旋转二维数组的需求。在寻找最佳解决方案时,我发现了这种令人印象深刻的一线功能:

rotated = zip(*original[::-1])

我现在在程序中使用它,它按预期工作。我的问题是,我不了解它是如何工作的。

如果有人可以解释所涉及的不同功能如何实现所需的结果,我将不胜感激。

In a program I’m writing the need to rotate a two-dimensional array came up. Searching for the optimal solution I found this impressive one-liner that does the job:

rotated = zip(*original[::-1])

I’m using it in my program now and it works as supposed. My problem though, is that I don’t understand how it works.

I’d appreciate if someone could explain how the different functions involved achieves the desired result.


回答 0

考虑以下二维列表:

original = [[1, 2],
            [3, 4]]

让我们将其逐步分解:

>>> original[::-1]   # elements of original are reversed
[[3, 4], [1, 2]]

此列表传递给zip()使用参数unpacking,因此zip调用最终等效于此:

zip([3, 4],
    [1, 2])
#    ^  ^----column 2
#    |-------column 1
# returns [(3, 1), (4, 2)], which is a original rotated clockwise

希望注释能够清楚说明其zip作用,它将基于索引将来自每个可迭代输入的元素进行分组,或者换句话说,将列进行分组。

Consider the following two-dimensional list:

original = [[1, 2],
            [3, 4]]

Lets break it down step by step:

>>> original[::-1]   # elements of original are reversed
[[3, 4], [1, 2]]

This list is passed into zip() using argument unpacking, so the zip call ends up being the equivalent of this:

zip([3, 4],
    [1, 2])
#    ^  ^----column 2
#    |-------column 1
# returns [(3, 1), (4, 2)], which is a original rotated clockwise

Hopefully the comments make it clear what zip does, it will group elements from each input iterable based on index, or in other words it groups the columns.


回答 1

太聪明了。

首先,如注释中所述,在Python 3中zip()返回一个迭代器,因此您需要将整个内容封装起来list()以得到实际的列表,因此从2020年开始实际上是:

list(zip(*original[::-1]))

这是细分:

  • [::-1]-以相反的顺序对原始列表进行浅表复制。也可以使用reversed()which来在列表上生成反向迭代器,而不是实际复制列表(更节省内存)。
  • *-使原始列表中的每个子列表成为一个单独的参数zip()(即,解压缩列表)
  • zip()-从每个参数中取出一个项目,并从中得到一个列表(以及一个元组),然后重复进行直到所有子列表都用尽。这是换位实际发生的地方。
  • list()将的输出转换zip()为列表。

所以假设你有这个:

[ [1, 2, 3],
  [4, 5, 6],
  [7, 8, 9] ]

您首先得到以下内容(浅色,反向副本):

[ [7, 8, 9],
  [4, 5, 6],
  [1, 2, 3] ]

接下来,每个子列表作为参数传递给zip

zip([7, 8, 9], [4, 5, 6], [1, 2, 3])

zip() 从其每个参数的开头重复消耗一个项目,并根据它生成一个元组,直到没有更多项目为止,结果是(将其转换为列表之后):

[(7, 4, 1), 
 (8, 5, 2), 
 (9, 6, 3)]

而鲍勃是你的叔叔。

要在有关将IkMiguel朝另一个方向旋转的评论中回答@IkeMiguel的问题,这非常简单:您只需要反转进入的序列zip和结果。第一个可以通过删除来实现,[::-1]第二个可以通过将reversed()整个对象扔掉来实现。由于reversed()回报率在列表上的迭代器,我们需要把list()周围将其转换。通过几次额外的list()调用将迭代器转换为实际列表。所以:

rotated = list(reversed(list(zip(*original))))

我们可以使用“火星人的笑脸”切片而不是reversed()… 来简化一点,那么我们不需要外部的list()

rotated = list(zip(*original))[::-1]

当然,您也可以简单地将列表顺时针旋转三下。:-)

That’s a clever bit.

First, as noted in a comment, in Python 3 zip() returns an iterator, so you need to enclose the whole thing in list() to get an actual list back out, so as of 2020 it’s actually:

list(zip(*original[::-1]))

Here’s the breakdown:

  • [::-1] – makes a shallow copy of the original list in reverse order. Could also use reversed() which would produce a reverse iterator over the list rather than actually copying the list (more memory efficient).
  • * – makes each sublist in the original list a separate argument to zip() (i.e., unpacks the list)
  • zip() – takes one item from each argument and makes a list (well, a tuple) from those, and repeats until all the sublists are exhausted. This is where the transposition actually happens.
  • list() converts the output of zip() to a list.

So assuming you have this:

[ [1, 2, 3],
  [4, 5, 6],
  [7, 8, 9] ]

You first get this (shallow, reversed copy):

[ [7, 8, 9],
  [4, 5, 6],
  [1, 2, 3] ]

Next each of the sublists is passed as an argument to zip:

zip([7, 8, 9], [4, 5, 6], [1, 2, 3])

zip() repeatedly consumes one item from the beginning of each of its arguments and makes a tuple from it, until there are no more items, resulting in (after it’s converted to a list):

[(7, 4, 1), 
 (8, 5, 2), 
 (9, 6, 3)]

And Bob’s your uncle.

To answer @IkeMiguel’s question in a comment about rotating it in the other direction, it’s pretty straightforward: you just need to reverse both the sequences that go into zip and the result. The first can be achieved by removing the [::-1] and the second can be achieved by throwing a reversed() around the whole thing. Since reversed() returns an iterator over the list, we will need to put list() around that to convert it. With a couple extra list() calls to convert the iterators to an actual list. So:

rotated = list(reversed(list(zip(*original))))

We can simplify that a bit by using the “Martian smiley” slice rather than reversed()… then we don’t need the outer list():

rotated = list(zip(*original))[::-1]

Of course, you could also simply rotate the list clockwise three times. :-)


回答 2

这包括三个部分:

  1. original [::-1]反转原始数组。该表示法是Python列表切片。这为您提供了[start:end:step]描述的原始列表的“子列表”,start是要在子列表中使用的第一个元素,end是最后一个要使用的元素。步骤说从头到尾走每一步。省略开始和结束意味着切片将是整个列表,而否定步骤意味着您将获得相反的元素。因此,例如,如果原始值为[x,y,z],则结果将为[z,y,x]
  2. *在函数调用的参数列表中的列表/元组前面时,*表示“扩展”列表/元组,以便其每个元素成为函数的单独参数,而不是列表/元组本身。因此,如果args = [1,2,3],则zip(args)与zip([1,2,3])相同,但是zip(* args)与zip(1, 2,3)。
  3. zip是一个函数,它接受n个参数,每个参数的长度为m,并生成一个长度为m的列表,其中的元素的长度为n,并包含每个原始列表的对应元素。例如,zip([1,2 ,, [a,b],[x,y])是[[1,a,x],[2,b,y]]。另请参阅Python文档。

There are three parts to this:

  1. original[::-1] reverses the original array. This notation is Python list slicing. This gives you a “sublist” of the original list described by [start:end:step], start is the first element, end is the last element to be used in the sublist. step says take every step’th element from first to last. Omitted start and end means the slice will be the entire list, and the negative step means that you’ll get the elements in reverse. So, for example, if original was [x,y,z], the result would be [z,y,x]
  2. The * when preceding a list/tuple in the argument list of a function call means “expand” the list/tuple so that each of its elements becomes a separate argument to the function, rather than the list/tuple itself. So that if, say, args = [1,2,3], then zip(args) is the same as zip([1,2,3]), but zip(*args) is the same as zip(1,2,3).
  3. zip is a function that takes n arguments each of which is of length m and produces a list of length m, the elements of are of length n and contain the corresponding elements of each of the original lists. E.g., zip([1,2],[a,b],[x,y]) is [[1,a,x],[2,b,y]]. See also Python documentation.

回答 3

只是一个观察。输入是一个列表列表,但是非常好的解决方案的输出:旋转= zip(* original [::-1])返回一个元组列表。

这可能是问题,也可能不是问题。

但是,它很容易纠正:

original = [[1, 2, 3],
            [4, 5, 6],
            [7, 8, 9]
            ]


def rotated(array_2d):
    list_of_tuples = zip(*array_2d[::-1])
    return [list(elem) for elem in list_of_tuples]
    # return map(list, list_of_tuples)

print(list(rotated(original)))

# [[7, 4, 1], [8, 5, 2], [9, 6, 3]]

list comp或map都将内部元组转换回list。

Just an observation. The input is a list of lists, but the output from the very nice solution: rotated = zip(*original[::-1]) returns a list of tuples.

This may or may not be an issue.

It is, however, easily corrected:

original = [[1, 2, 3],
            [4, 5, 6],
            [7, 8, 9]
            ]


def rotated(array_2d):
    list_of_tuples = zip(*array_2d[::-1])
    return [list(elem) for elem in list_of_tuples]
    # return map(list, list_of_tuples)

print(list(rotated(original)))

# [[7, 4, 1], [8, 5, 2], [9, 6, 3]]

The list comp or the map will both convert the interior tuples back to lists.


回答 4

def ruota_orario(matrix):
   ruota=list(zip(*reversed(matrix)))
   return[list(elemento) for elemento in ruota]
def ruota_antiorario(matrix):
   ruota=list(zip(*reversed(matrix)))
   return[list(elemento)[::-1] for elemento in ruota][::-1]
def ruota_orario(matrix):
   ruota=list(zip(*reversed(matrix)))
   return[list(elemento) for elemento in ruota]
def ruota_antiorario(matrix):
   ruota=list(zip(*reversed(matrix)))
   return[list(elemento)[::-1] for elemento in ruota][::-1]

回答 5

我自己遇到了这个问题,并且找到了关于该主题的出色维基百科页面(在“常见轮换”段落中:
https //en.wikipedia.org/wiki/Rotation_matrix#Ambiguities

然后,我编写了以下超级冗长的代码,以便对发生的事情有一个清晰的了解。

我希望您会发现在您发布的非常漂亮和聪明的单线中进行更多挖掘很有用。

要快速测试它,您可以在此处复制/粘贴它:http :
//www.codeskulptor.org/

triangle = [[0,0],[5,0],[5,2]]
coordinates_a = triangle[0]
coordinates_b = triangle[1]
coordinates_c = triangle[2]

def rotate90ccw(coordinates):
    print "Start coordinates:"
    print coordinates
    old_x = coordinates[0]
    old_y = coordinates[1]
# Here we apply the matrix coming from Wikipedia
# for 90 ccw it looks like:
# 0,-1
# 1,0
# What does this mean?
#
# Basically this is how the calculation of the new_x and new_y is happening:
# new_x = (0)(old_x)+(-1)(old_y)
# new_y = (1)(old_x)+(0)(old_y)
#
# If you check the lonely numbers between parenthesis the Wikipedia matrix's numbers
# finally start making sense.
# All the rest is standard formula, the same behaviour will apply to other rotations, just
# remember to use the other rotation matrix values available on Wiki for 180ccw and 170ccw
    new_x = -old_y
    new_y = old_x
    print "End coordinates:"
    print [new_x, new_y]

def rotate180ccw(coordinates):
    print "Start coordinates:"
    print coordinates
    old_x = coordinates[0]
    old_y = coordinates[1] 
    new_x = -old_x
    new_y = -old_y
    print "End coordinates:"
    print [new_x, new_y]

def rotate270ccw(coordinates):
    print "Start coordinates:"
    print coordinates
    old_x = coordinates[0]
    old_y = coordinates[1]  
    new_x = -old_x
    new_y = -old_y
    print "End coordinates:"
    print [new_x, new_y]

print "Let's rotate point A 90 degrees ccw:"
rotate90ccw(coordinates_a)
print "Let's rotate point B 90 degrees ccw:"
rotate90ccw(coordinates_b)
print "Let's rotate point C 90 degrees ccw:"
rotate90ccw(coordinates_c)
print "=== === === === === === === === === "
print "Let's rotate point A 180 degrees ccw:"
rotate180ccw(coordinates_a)
print "Let's rotate point B 180 degrees ccw:"
rotate180ccw(coordinates_b)
print "Let's rotate point C 180 degrees ccw:"
rotate180ccw(coordinates_c)
print "=== === === === === === === === === "
print "Let's rotate point A 270 degrees ccw:"
rotate270ccw(coordinates_a)
print "Let's rotate point B 270 degrees ccw:"
rotate270ccw(coordinates_b)
print "Let's rotate point C 270 degrees ccw:"
rotate270ccw(coordinates_c)
print "=== === === === === === === === === "

I’ve had this problem myself and I’ve found the great wikipedia page on the subject (in “Common rotations” paragraph:
https://en.wikipedia.org/wiki/Rotation_matrix#Ambiguities

Then I wrote the following code, super verbose in order to have a clear understanding of what is going on.

I hope that you’ll find it useful to dig more in the very beautiful and clever one-liner you’ve posted.

To quickly test it you can copy / paste it here:
http://www.codeskulptor.org/

triangle = [[0,0],[5,0],[5,2]]
coordinates_a = triangle[0]
coordinates_b = triangle[1]
coordinates_c = triangle[2]

def rotate90ccw(coordinates):
    print "Start coordinates:"
    print coordinates
    old_x = coordinates[0]
    old_y = coordinates[1]
# Here we apply the matrix coming from Wikipedia
# for 90 ccw it looks like:
# 0,-1
# 1,0
# What does this mean?
#
# Basically this is how the calculation of the new_x and new_y is happening:
# new_x = (0)(old_x)+(-1)(old_y)
# new_y = (1)(old_x)+(0)(old_y)
#
# If you check the lonely numbers between parenthesis the Wikipedia matrix's numbers
# finally start making sense.
# All the rest is standard formula, the same behaviour will apply to other rotations, just
# remember to use the other rotation matrix values available on Wiki for 180ccw and 170ccw
    new_x = -old_y
    new_y = old_x
    print "End coordinates:"
    print [new_x, new_y]

def rotate180ccw(coordinates):
    print "Start coordinates:"
    print coordinates
    old_x = coordinates[0]
    old_y = coordinates[1] 
    new_x = -old_x
    new_y = -old_y
    print "End coordinates:"
    print [new_x, new_y]

def rotate270ccw(coordinates):
    print "Start coordinates:"
    print coordinates
    old_x = coordinates[0]
    old_y = coordinates[1]  
    new_x = -old_x
    new_y = -old_y
    print "End coordinates:"
    print [new_x, new_y]

print "Let's rotate point A 90 degrees ccw:"
rotate90ccw(coordinates_a)
print "Let's rotate point B 90 degrees ccw:"
rotate90ccw(coordinates_b)
print "Let's rotate point C 90 degrees ccw:"
rotate90ccw(coordinates_c)
print "=== === === === === === === === === "
print "Let's rotate point A 180 degrees ccw:"
rotate180ccw(coordinates_a)
print "Let's rotate point B 180 degrees ccw:"
rotate180ccw(coordinates_b)
print "Let's rotate point C 180 degrees ccw:"
rotate180ccw(coordinates_c)
print "=== === === === === === === === === "
print "Let's rotate point A 270 degrees ccw:"
rotate270ccw(coordinates_a)
print "Let's rotate point B 270 degrees ccw:"
rotate270ccw(coordinates_b)
print "Let's rotate point C 270 degrees ccw:"
rotate270ccw(coordinates_c)
print "=== === === === === === === === === "

回答 6

逆时针旋转(标准列到行枢轴)作为列表和Dict

rows = [
  ['A', 'B', 'C', 'D'],
  [1,2,3,4],
  [1,2,3],
  [1,2],
  [1],
]

pivot = []

for row in rows:
  for column, cell in enumerate(row):
    if len(pivot) == column: pivot.append([])
    pivot[column].append(cell)

print(rows)
print(pivot)
print(dict([(row[0], row[1:]) for row in pivot]))

生成:

[['A', 'B', 'C', 'D'], [1, 2, 3, 4], [1, 2, 3], [1, 2], [1]]
[['A', 1, 1, 1, 1], ['B', 2, 2, 2], ['C', 3, 3], ['D', 4]]
{'A': [1, 1, 1, 1], 'B': [2, 2, 2], 'C': [3, 3], 'D': [4]}

Rotating Counter Clockwise ( standard column to row pivot ) As List and Dict

rows = [
  ['A', 'B', 'C', 'D'],
  [1,2,3,4],
  [1,2,3],
  [1,2],
  [1],
]

pivot = []

for row in rows:
  for column, cell in enumerate(row):
    if len(pivot) == column: pivot.append([])
    pivot[column].append(cell)

print(rows)
print(pivot)
print(dict([(row[0], row[1:]) for row in pivot]))

Produces:

[['A', 'B', 'C', 'D'], [1, 2, 3, 4], [1, 2, 3], [1, 2], [1]]
[['A', 1, 1, 1, 1], ['B', 2, 2, 2], ['C', 3, 3], ['D', 4]]
{'A': [1, 1, 1, 1], 'B': [2, 2, 2], 'C': [3, 3], 'D': [4]}

在numpy中将一维数组转换为二维数组

问题:在numpy中将一维数组转换为二维数组

我想通过指定2D数组中的列数将一维数组转换为二维数组。可能会像这样工作:

> import numpy as np
> A = np.array([1,2,3,4,5,6])
> B = vec2matrix(A,ncol=2)
> B
array([[1, 2],
       [3, 4],
       [5, 6]])

numpy是否具有类似于我的组合函数“ vec2matrix”的功能?(我知道您可以像2D数组一样索引1D数组,但这不是我拥有的代码中的选项-我需要进行此转换。)

I want to convert a 1-dimensional array into a 2-dimensional array by specifying the number of columns in the 2D array. Something that would work like this:

> import numpy as np
> A = np.array([1,2,3,4,5,6])
> B = vec2matrix(A,ncol=2)
> B
array([[1, 2],
       [3, 4],
       [5, 6]])

Does numpy have a function that works like my made-up function “vec2matrix”? (I understand that you can index a 1D array like a 2D array, but that isn’t an option in the code I have – I need to make this conversion.)


回答 0

您要reshape阵列。

B = np.reshape(A, (-1, 2))

其中-1,从输入数组的大小推断出新维度的大小。

You want to reshape the array.

B = np.reshape(A, (-1, 2))

where -1 infers the size of the new dimension from the size of the input array.


回答 1

您有两种选择:

  • 如果您不再想要原始形状,最简单的方法就是为数组分配一个新形状

    a.shape = (a.size//ncols, ncols)

    您可以切换a.size//ncols通过-1自动计算合适的形状。确保a.shape[0]*a.shape[1]=a.size,否则会遇到一些问题。

  • 您可以使用np.reshape函数获得一个新的数组,该函数的工作原理与上述版本相似

    new = np.reshape(a, (-1, ncols))

    如果可能,new将仅是初始array的视图a,这意味着数据是共享的。但是,在某些情况下,new数组将被复制。请注意,np.reshape还接受一个可选关键字order,该关键字使您可以从行优先C顺序切换到列优先Fortran顺序。np.reshape是该a.reshape方法的函数版本。

如果您不能满足要求a.shape[0]*a.shape[1]=a.size,则必须创建一个新数组。您可以使用该np.resize函数并将其与混合使用np.reshape,例如

>>> a =np.arange(9)
>>> np.resize(a, 10).reshape(5,2)

You have two options:

  • If you no longer want the original shape, the easiest is just to assign a new shape to the array

    a.shape = (a.size//ncols, ncols)
    

    You can switch the a.size//ncols by -1 to compute the proper shape automatically. Make sure that a.shape[0]*a.shape[1]=a.size, else you’ll run into some problem.

  • You can get a new array with the np.reshape function, that works mostly like the version presented above

    new = np.reshape(a, (-1, ncols))
    

    When it’s possible, new will be just a view of the initial array a, meaning that the data are shared. In some cases, though, new array will be acopy instead. Note that np.reshape also accepts an optional keyword order that lets you switch from row-major C order to column-major Fortran order. np.reshape is the function version of the a.reshape method.

If you can’t respect the requirement a.shape[0]*a.shape[1]=a.size, you’re stuck with having to create a new array. You can use the np.resize function and mixing it with np.reshape, such as

>>> a =np.arange(9)
>>> np.resize(a, 10).reshape(5,2)

回答 2

尝试类似的方法:

B = np.reshape(A,(-1,ncols))

您需要确保可以将数组中的元素数除以ncols。您也可以B使用order关键字按照将数字拉入的顺序进行游戏。

Try something like:

B = np.reshape(A,(-1,ncols))

You’ll need to make sure that you can divide the number of elements in your array by ncols though. You can also play with the order in which the numbers are pulled into B using the order keyword.


回答 3

如果您的唯一目的是将1d数组X转换为2d数组,请执行以下操作:

X = np.reshape(X,(1, X.size))

If your sole purpose is to convert a 1d array X to a 2d array just do:

X = np.reshape(X,(1, X.size))

回答 4

import numpy as np
array = np.arange(8) 
print("Original array : \n", array)
array = np.arange(8).reshape(2, 4)
print("New array : \n", array)
import numpy as np
array = np.arange(8) 
print("Original array : \n", array)
array = np.arange(8).reshape(2, 4)
print("New array : \n", array)

回答 5

some_array.shape = (1,)+some_array.shape

或换一个新的

another_array = numpy.reshape(some_array, (1,)+some_array.shape)

这将使尺寸+1,等于在最外层添加一个括号

some_array.shape = (1,)+some_array.shape

or get a new one

another_array = numpy.reshape(some_array, (1,)+some_array.shape)

This will make dimensions +1, equals to adding a bracket on the outermost


回答 6

您可以flatten()从numpy包中使用。

import numpy as np
a = np.array([[1, 2],
       [3, 4],
       [5, 6]])
a_flat = a.flatten()
print(f"original array: {a} \nflattened array = {a_flat}")

输出:

original array: [[1 2]
 [3 4]
 [5 6]] 
flattened array = [1 2 3 4 5 6]

You can useflatten() from the numpy package.

import numpy as np
a = np.array([[1, 2],
       [3, 4],
       [5, 6]])
a_flat = a.flatten()
print(f"original array: {a} \nflattened array = {a_flat}")

Output:

original array: [[1 2]
 [3 4]
 [5 6]] 
flattened array = [1 2 3 4 5 6]

回答 7

不使用Numpy将一维数组更改为二维数组。

l = [i for i in range(1,21)]
part = 3
new = []
start, end = 0, part


while end <= len(l):
    temp = []
    for i in range(start, end):
        temp.append(l[i])
    new.append(temp)
    start += part
    end += part
print("new values:  ", new)


# for uneven cases
temp = []
while start < len(l):
    temp.append(l[start])
    start += 1
    new.append(temp)
print("new values for uneven cases:   ", new)

Change 1D array into 2D array without using Numpy.

l = [i for i in range(1,21)]
part = 3
new = []
start, end = 0, part


while end <= len(l):
    temp = []
    for i in range(start, end):
        temp.append(l[i])
    new.append(temp)
    start += part
    end += part
print("new values:  ", new)


# for uneven cases
temp = []
while start < len(l):
    temp.append(l[start])
    start += 1
    new.append(temp)
print("new values for uneven cases:   ", new)

从NumPy数组中选择特定的行和列

问题:从NumPy数组中选择特定的行和列

我一直在发疯,试图找出我在这里做错了什么愚蠢的事情。

我正在使用NumPy,并且我想从中选择特定的行索引和特定的列索引。这是我的问题的要点:

import numpy as np

a = np.arange(20).reshape((5,4))
# array([[ 0,  1,  2,  3],
#        [ 4,  5,  6,  7],
#        [ 8,  9, 10, 11],
#        [12, 13, 14, 15],
#        [16, 17, 18, 19]])

# If I select certain rows, it works
print a[[0, 1, 3], :]
# array([[ 0,  1,  2,  3],
#        [ 4,  5,  6,  7],
#        [12, 13, 14, 15]])

# If I select certain rows and a single column, it works
print a[[0, 1, 3], 2]
# array([ 2,  6, 14])

# But if I select certain rows AND certain columns, it fails
print a[[0,1,3], [0,2]]
# Traceback (most recent call last):
#   File "<stdin>", line 1, in <module>
# ValueError: shape mismatch: objects cannot be broadcast to a single shape

为什么会这样呢?我当然应该能够选择第一行,第二行和第四行以及第一列和第三列?我期望的结果是:

a[[0,1,3], [0,2]] => [[0,  2],
                      [4,  6],
                      [12, 14]]

I’ve been going crazy trying to figure out what stupid thing I’m doing wrong here.

I’m using NumPy, and I have specific row indices and specific column indices that I want to select from. Here’s the gist of my problem:

import numpy as np

a = np.arange(20).reshape((5,4))
# array([[ 0,  1,  2,  3],
#        [ 4,  5,  6,  7],
#        [ 8,  9, 10, 11],
#        [12, 13, 14, 15],
#        [16, 17, 18, 19]])

# If I select certain rows, it works
print a[[0, 1, 3], :]
# array([[ 0,  1,  2,  3],
#        [ 4,  5,  6,  7],
#        [12, 13, 14, 15]])

# If I select certain rows and a single column, it works
print a[[0, 1, 3], 2]
# array([ 2,  6, 14])

# But if I select certain rows AND certain columns, it fails
print a[[0,1,3], [0,2]]
# Traceback (most recent call last):
#   File "<stdin>", line 1, in <module>
# ValueError: shape mismatch: objects cannot be broadcast to a single shape

Why is this happening? Surely I should be able to select the 1st, 2nd, and 4th rows, and 1st and 3rd columns? The result I’m expecting is:

a[[0,1,3], [0,2]] => [[0,  2],
                      [4,  6],
                      [12, 14]]

回答 0

花式索引要求您提供每个维度的所有索引。您为第一个提供3个索引,为第二个仅提供2个索引,因此会出现错误。您想做这样的事情:

>>> a[[[0, 0], [1, 1], [3, 3]], [[0,2], [0,2], [0, 2]]]
array([[ 0,  2],
       [ 4,  6],
       [12, 14]])

当然写这很痛苦,所以您可以让广播帮助您:

>>> a[[[0], [1], [3]], [0, 2]]
array([[ 0,  2],
       [ 4,  6],
       [12, 14]])

如果您使用数组而不是列表建立索引,则此操作要简单得多:

>>> row_idx = np.array([0, 1, 3])
>>> col_idx = np.array([0, 2])
>>> a[row_idx[:, None], col_idx]
array([[ 0,  2],
       [ 4,  6],
       [12, 14]])

Fancy indexing requires you to provide all indices for each dimension. You are providing 3 indices for the first one, and only 2 for the second one, hence the error. You want to do something like this:

>>> a[[[0, 0], [1, 1], [3, 3]], [[0,2], [0,2], [0, 2]]]
array([[ 0,  2],
       [ 4,  6],
       [12, 14]])

That is of course a pain to write, so you can let broadcasting help you:

>>> a[[[0], [1], [3]], [0, 2]]
array([[ 0,  2],
       [ 4,  6],
       [12, 14]])

This is much simpler to do if you index with arrays, not lists:

>>> row_idx = np.array([0, 1, 3])
>>> col_idx = np.array([0, 2])
>>> a[row_idx[:, None], col_idx]
array([[ 0,  2],
       [ 4,  6],
       [12, 14]])

回答 1

至于全胜表明,一个简单的黑客是只选择第一行,然后选择在列

>>> a[[0,1,3], :]            # Returns the rows you want
array([[ 0,  1,  2,  3],
       [ 4,  5,  6,  7],
       [12, 13, 14, 15]])
>>> a[[0,1,3], :][:, [0,2]]  # Selects the columns you want as well
array([[ 0,  2],
       [ 4,  6],
       [12, 14]])

[编辑]内置方法: np.ix_

最近,我发现numpy为您提供了内置的一线功能,可以准确执行@Jaime的建议,而不必使用广播语法(由于缺乏可读性)。从文档:

使用ix_可以快速构建索引数组,该索引数组将对叉积进行索引。a[np.ix_([1,3],[2,5])]返回数组[[a[1,2] a[1,5]], [a[3,2] a[3,5]]]

因此,您可以这样使用它:

>>> a = np.arange(20).reshape((5,4))
>>> a[np.ix_([0,1,3], [0,2])]
array([[ 0,  2],
       [ 4,  6],
       [12, 14]])

而且它的工作方式是像Jaime所建议的那样照顾数组的对齐,以便正确进行广播:

>>> np.ix_([0,1,3], [0,2])
(array([[0],
        [1],
        [3]]), array([[0, 2]]))

而且,正如MikeC在评论中说的那样,它np.ix_具有返回视图的优点,而我的第一个(预编辑)答案没有。这意味着您现在可以分配给索引数组:

>>> a[np.ix_([0,1,3], [0,2])] = -1
>>> a    
array([[-1,  1, -1,  3],
       [-1,  5, -1,  7],
       [ 8,  9, 10, 11],
       [-1, 13, -1, 15],
       [16, 17, 18, 19]])

As Toan suggests, a simple hack would be to just select the rows first, and then select the columns over that.

>>> a[[0,1,3], :]            # Returns the rows you want
array([[ 0,  1,  2,  3],
       [ 4,  5,  6,  7],
       [12, 13, 14, 15]])
>>> a[[0,1,3], :][:, [0,2]]  # Selects the columns you want as well
array([[ 0,  2],
       [ 4,  6],
       [12, 14]])

[Edit] The built-in method: np.ix_

I recently discovered that numpy gives you an in-built one-liner to doing exactly what @Jaime suggested, but without having to use broadcasting syntax (which suffers from lack of readability). From the docs:

Using ix_ one can quickly construct index arrays that will index the cross product. a[np.ix_([1,3],[2,5])] returns the array [[a[1,2] a[1,5]], [a[3,2] a[3,5]]].

So you use it like this:

>>> a = np.arange(20).reshape((5,4))
>>> a[np.ix_([0,1,3], [0,2])]
array([[ 0,  2],
       [ 4,  6],
       [12, 14]])

And the way it works is that it takes care of aligning arrays the way Jaime suggested, so that broadcasting happens properly:

>>> np.ix_([0,1,3], [0,2])
(array([[0],
        [1],
        [3]]), array([[0, 2]]))

Also, as MikeC says in a comment, np.ix_ has the advantage of returning a view, which my first (pre-edit) answer did not. This means you can now assign to the indexed array:

>>> a[np.ix_([0,1,3], [0,2])] = -1
>>> a    
array([[-1,  1, -1,  3],
       [-1,  5, -1,  7],
       [ 8,  9, 10, 11],
       [-1, 13, -1, 15],
       [16, 17, 18, 19]])

回答 2

使用:

 >>> a[[0,1,3]][:,[0,2]]
array([[ 0,  2],
   [ 4,  6],
   [12, 14]])

要么:

>>> a[[0,1,3],::2]
array([[ 0,  2],
   [ 4,  6],
   [12, 14]])

USE:

 >>> a[[0,1,3]][:,[0,2]]
array([[ 0,  2],
   [ 4,  6],
   [12, 14]])

OR:

>>> a[[0,1,3],::2]
array([[ 0,  2],
   [ 4,  6],
   [12, 14]])

回答 3

使用np.ix_是最方便的方法(有人回答),但这是另一种有趣的方法:

>>> rows = [0, 1, 3]
>>> cols = [0, 2]

>>> a[rows].T[cols].T

array([[ 0,  2],
       [ 4,  6],
       [12, 14]])

Using np.ix_ is the most convenient way to do it (as answered by others), but here is another interesting way to do it:

>>> rows = [0, 1, 3]
>>> cols = [0, 2]

>>> a[rows].T[cols].T

array([[ 0,  2],
       [ 4,  6],
       [12, 14]])

numpy数组的argmax返回非固定索引

问题:numpy数组的argmax返回非固定索引

我正在尝试获取Numpy数组中最大元素的索引。可以使用来完成numpy.argmax。我的问题是,我想在整个数组中找到最大的元素并获取其索引。

numpy.argmax 既可以沿一个轴(不是我想要的)应用,也可以沿扁平数组(这是我想要的一种)应用。

我的问题是,当我想要多维索引时,使用numpy.argmaxwithaxis=None返回平面索引。

我可以divmod用来获取非固定索引,但这很难看。有什么更好的方法吗?

I’m trying to get the indices of the maximum element in a Numpy array. This can be done using numpy.argmax. My problem is, that I would like to find the biggest element in the whole array and get the indices of that.

numpy.argmax can be either applied along one axis, which is not what I want, or on the flattened array, which is kind of what I want.

My problem is that using numpy.argmax with axis=None returns the flat index when I want the multi-dimensional index.

I could use divmod to get a non-flat index but this feels ugly. Is there any better way of doing this?


回答 0

您可以使用numpy.unravel_index()以下结果numpy.argmax()

>>> a = numpy.random.random((10, 10))
>>> numpy.unravel_index(a.argmax(), a.shape)
(6, 7)
>>> a[6, 7] == a.max()
True

You could use numpy.unravel_index() on the result of numpy.argmax():

>>> a = numpy.random.random((10, 10))
>>> numpy.unravel_index(a.argmax(), a.shape)
(6, 7)
>>> a[6, 7] == a.max()
True

回答 1

np.where(a==a.max())

返回最大元素的坐标,但必须将数组解析两次。

>>> a = np.array(((3,4,5),(0,1,2)))
>>> np.where(a==a.max())
(array([0]), array([2]))

与相比argmax,这将返回等于最大值的所有元素的坐标。argmax仅返回其中之一(np.ones(5).argmax()return 0)。

np.where(a==a.max())

returns coordinates of the maximum element(s), but has to parse the array twice.

>>> a = np.array(((3,4,5),(0,1,2)))
>>> np.where(a==a.max())
(array([0]), array([2]))

This, comparing to argmax, returns coordinates of all elements equal to the maximum. argmax returns just one of them (np.ones(5).argmax() returns 0).


回答 2

要获取所有出现的最大值的非平坦索引,可以使用代替来稍微修改eumiro的答案argwherewhere

np.argwhere(a==a.max())

>>> a = np.array([[1,2,4],[4,3,4]])
>>> np.argwhere(a==a.max())
array([[0, 2],
       [1, 0],
       [1, 2]])

To get the non-flat index of all occurrences of the maximum value, you can modify eumiro’s answer slightly by using argwhere instead of where:

np.argwhere(a==a.max())

>>> a = np.array([[1,2,4],[4,3,4]])
>>> np.argwhere(a==a.max())
array([[0, 2],
       [1, 0],
       [1, 2]])

使用numpy构建两个数组的所有组合的数组

问题:使用numpy构建两个数组的所有组合的数组

我试图在尝试使用6参数函数的参数空间之前先研究它的数值行为,然后再尝试对其进行复杂的处理,因此我正在寻找一种有效的方法来执行此操作。

我的函数采用给定6维numpy数组作为输入的float值。我最初尝试做的是:

首先,我创建了一个函数,该函数接受2个数组并生成一个包含两个数组中值的所有组合的数组

from numpy import *
def comb(a,b):
    c = []
    for i in a:
        for j in b:
            c.append(r_[i,j])
    return c

然后我将reduce()其应用于同一数组的m个副本:

def combs(a,m):
    return reduce(comb,[a]*m)

然后我像这样评估我的功能:

values = combs(np.arange(0,1,0.1),6)
for val in values:
    print F(val)

这有效,但是太慢了。我知道参数的空间很大,但这不应该太慢。在此示例中,我仅采样了10 6(一百万)个点,仅花费了15秒以上的时间便创建了数组values

您知道使用numpy进行此操作的更有效的方法吗?

F如果需要,我可以修改函数接受参数的方式。

I’m trying to run over the parameters space of a 6 parameter function to study it’s numerical behavior before trying to do anything complex with it so I’m searching for a efficient way to do this.

My function takes float values given a 6-dim numpy array as input. What I tried to do initially was this:

First I created a function that takes 2 arrays and generate an array with all combinations of values from the two arrays

from numpy import *
def comb(a,b):
    c = []
    for i in a:
        for j in b:
            c.append(r_[i,j])
    return c

Then I used reduce() to apply that to m copies of the same array:

def combs(a,m):
    return reduce(comb,[a]*m)

And then I evaluate my function like this:

values = combs(np.arange(0,1,0.1),6)
for val in values:
    print F(val)

This works but it’s waaaay too slow. I know the space of parameters is huge, but this shouldn’t be so slow. I have only sampled 106 (a million) points in this example and it took more than 15 seconds just to create the array values.

Do you know any more efficient way of doing this with numpy?

I can modify the way the function F takes it’s arguments if it’s necessary.


回答 0

numpy(> 1.8.x)的较新版本中,numpy.meshgrid()提供了更快的实现:

@PV的解决方案

In [113]:

%timeit cartesian(([1, 2, 3], [4, 5], [6, 7]))
10000 loops, best of 3: 135 µs per loop
In [114]:

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

Out[114]:
array([[1, 4, 6],
       [1, 4, 7],
       [1, 5, 6],
       [1, 5, 7],
       [2, 4, 6],
       [2, 4, 7],
       [2, 5, 6],
       [2, 5, 7],
       [3, 4, 6],
       [3, 4, 7],
       [3, 5, 6],
       [3, 5, 7]])

numpy.meshgrid()只能用于2D,现在可以ND。在这种情况下,3D:

In [115]:

%timeit np.array(np.meshgrid([1, 2, 3], [4, 5], [6, 7])).T.reshape(-1,3)
10000 loops, best of 3: 74.1 µs per loop
In [116]:

np.array(np.meshgrid([1, 2, 3], [4, 5], [6, 7])).T.reshape(-1,3)

Out[116]:
array([[1, 4, 6],
       [1, 5, 6],
       [2, 4, 6],
       [2, 5, 6],
       [3, 4, 6],
       [3, 5, 6],
       [1, 4, 7],
       [1, 5, 7],
       [2, 4, 7],
       [2, 5, 7],
       [3, 4, 7],
       [3, 5, 7]])

请注意,最终结果的顺序略有不同。

In newer version of numpy (>1.8.x), numpy.meshgrid() provides a much faster implementation:

@pv’s solution

In [113]:

%timeit cartesian(([1, 2, 3], [4, 5], [6, 7]))
10000 loops, best of 3: 135 µs per loop
In [114]:

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

Out[114]:
array([[1, 4, 6],
       [1, 4, 7],
       [1, 5, 6],
       [1, 5, 7],
       [2, 4, 6],
       [2, 4, 7],
       [2, 5, 6],
       [2, 5, 7],
       [3, 4, 6],
       [3, 4, 7],
       [3, 5, 6],
       [3, 5, 7]])

numpy.meshgrid() use to be 2D only, now it is capable of ND. In this case, 3D:

In [115]:

%timeit np.array(np.meshgrid([1, 2, 3], [4, 5], [6, 7])).T.reshape(-1,3)
10000 loops, best of 3: 74.1 µs per loop
In [116]:

np.array(np.meshgrid([1, 2, 3], [4, 5], [6, 7])).T.reshape(-1,3)

Out[116]:
array([[1, 4, 6],
       [1, 5, 6],
       [2, 4, 6],
       [2, 5, 6],
       [3, 4, 6],
       [3, 5, 6],
       [1, 4, 7],
       [1, 5, 7],
       [2, 4, 7],
       [2, 5, 7],
       [3, 4, 7],
       [3, 5, 7]])

Note that the order of the final resultant is slightly different.


回答 1

这是一个纯粹的numpy实现。它比使用itertools快约5倍。


import numpy as np

def cartesian(arrays, out=None):
    """
    Generate a cartesian product of input arrays.

    Parameters
    ----------
    arrays : list of array-like
        1-D arrays to form the cartesian product of.
    out : ndarray
        Array to place the cartesian product in.

    Returns
    -------
    out : ndarray
        2-D array of shape (M, len(arrays)) containing cartesian products
        formed of input arrays.

    Examples
    --------
    >>> cartesian(([1, 2, 3], [4, 5], [6, 7]))
    array([[1, 4, 6],
           [1, 4, 7],
           [1, 5, 6],
           [1, 5, 7],
           [2, 4, 6],
           [2, 4, 7],
           [2, 5, 6],
           [2, 5, 7],
           [3, 4, 6],
           [3, 4, 7],
           [3, 5, 6],
           [3, 5, 7]])

    """

    arrays = [np.asarray(x) for x in arrays]
    dtype = arrays[0].dtype

    n = np.prod([x.size for x in arrays])
    if out is None:
        out = np.zeros([n, len(arrays)], dtype=dtype)

    m = n / arrays[0].size
    out[:,0] = np.repeat(arrays[0], m)
    if arrays[1:]:
        cartesian(arrays[1:], out=out[0:m, 1:])
        for j in xrange(1, arrays[0].size):
            out[j*m:(j+1)*m, 1:] = out[0:m, 1:]
    return out

Here’s a pure-numpy implementation. It’s about 5× faster than using itertools.


import numpy as np

def cartesian(arrays, out=None):
    """
    Generate a cartesian product of input arrays.

    Parameters
    ----------
    arrays : list of array-like
        1-D arrays to form the cartesian product of.
    out : ndarray
        Array to place the cartesian product in.

    Returns
    -------
    out : ndarray
        2-D array of shape (M, len(arrays)) containing cartesian products
        formed of input arrays.

    Examples
    --------
    >>> cartesian(([1, 2, 3], [4, 5], [6, 7]))
    array([[1, 4, 6],
           [1, 4, 7],
           [1, 5, 6],
           [1, 5, 7],
           [2, 4, 6],
           [2, 4, 7],
           [2, 5, 6],
           [2, 5, 7],
           [3, 4, 6],
           [3, 4, 7],
           [3, 5, 6],
           [3, 5, 7]])

    """

    arrays = [np.asarray(x) for x in arrays]
    dtype = arrays[0].dtype

    n = np.prod([x.size for x in arrays])
    if out is None:
        out = np.zeros([n, len(arrays)], dtype=dtype)

    m = n / arrays[0].size
    out[:,0] = np.repeat(arrays[0], m)
    if arrays[1:]:
        cartesian(arrays[1:], out=out[0:m, 1:])
        for j in xrange(1, arrays[0].size):
            out[j*m:(j+1)*m, 1:] = out[0:m, 1:]
    return out

回答 2

通常,itertools.combinations是从Python容器中获取组合的最快方法(如果您实际上确实想要组合,即无重复且无顺序的安排;那不是您的代码看起来正在做的事情,但是我做不到判断这是因为您的代码有错误还是因为您使用了错误的术语)。

如果您想要的不是组合,则itertools中的其他迭代器productpermutations可能会为您提供更好的服务。例如,看起来您的代码与以下代码大致相同:

for val in itertools.product(np.arange(0, 1, 0.1), repeat=6):
    print F(val)

所有这些迭代器都会生成元组,而不是列表或numpy数组,因此,如果您的F对要专门获取一个numpy数组很挑剔,则您将不得不承担在每一步构造或清除和重新填充一个数组的额外开销。

itertools.combinations is in general the fastest way to get combinations from a Python container (if you do in fact want combinations, i.e., arrangements WITHOUT repetitions and independent of order; that’s not what your code appears to be doing, but I can’t tell whether that’s because your code is buggy or because you’re using the wrong terminology).

If you want something different than combinations perhaps other iterators in itertools, product or permutations, might serve you better. For example, it looks like your code is roughly the same as:

for val in itertools.product(np.arange(0, 1, 0.1), repeat=6):
    print F(val)

All of these iterators yield tuples, not lists or numpy arrays, so if your F is picky about getting specifically a numpy array you’ll have to accept the extra overhead of constructing or clearing and re-filling one at each step.


回答 3

你可以做这样的事情

import numpy as np

def cartesian_coord(*arrays):
    grid = np.meshgrid(*arrays)        
    coord_list = [entry.ravel() for entry in grid]
    points = np.vstack(coord_list).T
    return points

a = np.arange(4)  # fake data
print(cartesian_coord(*6*[a])

这使

array([[0, 0, 0, 0, 0, 0],
   [0, 0, 0, 0, 0, 1],
   [0, 0, 0, 0, 0, 2],
   ..., 
   [3, 3, 3, 3, 3, 1],
   [3, 3, 3, 3, 3, 2],
   [3, 3, 3, 3, 3, 3]])

You can do something like this

import numpy as np

def cartesian_coord(*arrays):
    grid = np.meshgrid(*arrays)        
    coord_list = [entry.ravel() for entry in grid]
    points = np.vstack(coord_list).T
    return points

a = np.arange(4)  # fake data
print(cartesian_coord(*6*[a])

which gives

array([[0, 0, 0, 0, 0, 0],
   [0, 0, 0, 0, 0, 1],
   [0, 0, 0, 0, 0, 2],
   ..., 
   [3, 3, 3, 3, 3, 1],
   [3, 3, 3, 3, 3, 2],
   [3, 3, 3, 3, 3, 3]])

回答 4

以下numpy实现应为大约。给定答案速度的2倍:

def cartesian2(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

The following numpy implementation should be approx. 2x the speed of the given answer:

def cartesian2(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

回答 5

看起来您想让网格评估您的功能,在这种情况下,您可以使用numpy.ogrid(打开)或numpy.mgrid(完善):

import numpy
my_grid = numpy.mgrid[[slice(0,1,0.1)]*6]

It looks like you want a grid to evaluate your function, in which case you can use numpy.ogrid (open) or numpy.mgrid (fleshed out):

import numpy
my_grid = numpy.mgrid[[slice(0,1,0.1)]*6]

回答 6

您可以使用 np.array(itertools.product(a, b))

you can use np.array(itertools.product(a, b))


回答 7

这是使用纯NumPy,没有递归,没有列表理解以及没有明确的for循环的另一种方式。它比原始答案慢20%,并且基于np.meshgrid。

def cartesian(*arrays):
    mesh = np.meshgrid(*arrays)  # standard numpy meshgrid
    dim = len(mesh)  # number of dimensions
    elements = mesh[0].size  # number of elements, any index will do
    flat = np.concatenate(mesh).ravel()  # flatten the whole meshgrid
    reshape = np.reshape(flat, (dim, elements)).T  # reshape and transpose
    return reshape

例如,

x = np.arange(3)
a = cartesian(x, x, x, x, x)
print(a)

[[0 0 0 0 0]
 [0 0 0 0 1]
 [0 0 0 0 2]
 ..., 
 [2 2 2 2 0]
 [2 2 2 2 1]
 [2 2 2 2 2]]

Here’s yet another way, using pure NumPy, no recursion, no list comprehension, and no explicit for loops. It’s about 20% slower than the original answer, and it’s based on np.meshgrid.

def cartesian(*arrays):
    mesh = np.meshgrid(*arrays)  # standard numpy meshgrid
    dim = len(mesh)  # number of dimensions
    elements = mesh[0].size  # number of elements, any index will do
    flat = np.concatenate(mesh).ravel()  # flatten the whole meshgrid
    reshape = np.reshape(flat, (dim, elements)).T  # reshape and transpose
    return reshape

For example,

x = np.arange(3)
a = cartesian(x, x, x, x, x)
print(a)

gives

[[0 0 0 0 0]
 [0 0 0 0 1]
 [0 0 0 0 2]
 ..., 
 [2 2 2 2 0]
 [2 2 2 2 1]
 [2 2 2 2 2]]

回答 8

对于一维数组(或平坦的python列表)的笛卡尔积的纯numpy实现,只需使用meshgrid(),用滚动轴transpose(),然后将形状整形为所需的输出:

 def cartprod(*arrays):
     N = len(arrays)
     return transpose(meshgrid(*arrays, indexing='ij'), 
                      roll(arange(N + 1), -1)).reshape(-1, N)

请注意,这具有最后一个轴更改最快的约定(“ C样式”或“行主要”)。

In [88]: cartprod([1,2,3], [4,8], [100, 200, 300, 400], [-5, -4])
Out[88]: 
array([[  1,   4, 100,  -5],
       [  1,   4, 100,  -4],
       [  1,   4, 200,  -5],
       [  1,   4, 200,  -4],
       [  1,   4, 300,  -5],
       [  1,   4, 300,  -4],
       [  1,   4, 400,  -5],
       [  1,   4, 400,  -4],
       [  1,   8, 100,  -5],
       [  1,   8, 100,  -4],
       [  1,   8, 200,  -5],
       [  1,   8, 200,  -4],
       [  1,   8, 300,  -5],
       [  1,   8, 300,  -4],
       [  1,   8, 400,  -5],
       [  1,   8, 400,  -4],
       [  2,   4, 100,  -5],
       [  2,   4, 100,  -4],
       [  2,   4, 200,  -5],
       [  2,   4, 200,  -4],
       [  2,   4, 300,  -5],
       [  2,   4, 300,  -4],
       [  2,   4, 400,  -5],
       [  2,   4, 400,  -4],
       [  2,   8, 100,  -5],
       [  2,   8, 100,  -4],
       [  2,   8, 200,  -5],
       [  2,   8, 200,  -4],
       [  2,   8, 300,  -5],
       [  2,   8, 300,  -4],
       [  2,   8, 400,  -5],
       [  2,   8, 400,  -4],
       [  3,   4, 100,  -5],
       [  3,   4, 100,  -4],
       [  3,   4, 200,  -5],
       [  3,   4, 200,  -4],
       [  3,   4, 300,  -5],
       [  3,   4, 300,  -4],
       [  3,   4, 400,  -5],
       [  3,   4, 400,  -4],
       [  3,   8, 100,  -5],
       [  3,   8, 100,  -4],
       [  3,   8, 200,  -5],
       [  3,   8, 200,  -4],
       [  3,   8, 300,  -5],
       [  3,   8, 300,  -4],
       [  3,   8, 400,  -5],
       [  3,   8, 400,  -4]])

如果要最快地更改第一轴(“ FORTRAN样式”或“主要列”),只需更改如下order参数reshape()reshape((-1, N), order='F')

For a pure numpy implementation of Cartesian product of 1D arrays (or flat python lists), just use meshgrid(), roll the axes with transpose(), and reshape to the desired ouput:

 def cartprod(*arrays):
     N = len(arrays)
     return transpose(meshgrid(*arrays, indexing='ij'), 
                      roll(arange(N + 1), -1)).reshape(-1, N)

Note this has the convention of last axis changing fastest (“C style” or “row-major”).

In [88]: cartprod([1,2,3], [4,8], [100, 200, 300, 400], [-5, -4])
Out[88]: 
array([[  1,   4, 100,  -5],
       [  1,   4, 100,  -4],
       [  1,   4, 200,  -5],
       [  1,   4, 200,  -4],
       [  1,   4, 300,  -5],
       [  1,   4, 300,  -4],
       [  1,   4, 400,  -5],
       [  1,   4, 400,  -4],
       [  1,   8, 100,  -5],
       [  1,   8, 100,  -4],
       [  1,   8, 200,  -5],
       [  1,   8, 200,  -4],
       [  1,   8, 300,  -5],
       [  1,   8, 300,  -4],
       [  1,   8, 400,  -5],
       [  1,   8, 400,  -4],
       [  2,   4, 100,  -5],
       [  2,   4, 100,  -4],
       [  2,   4, 200,  -5],
       [  2,   4, 200,  -4],
       [  2,   4, 300,  -5],
       [  2,   4, 300,  -4],
       [  2,   4, 400,  -5],
       [  2,   4, 400,  -4],
       [  2,   8, 100,  -5],
       [  2,   8, 100,  -4],
       [  2,   8, 200,  -5],
       [  2,   8, 200,  -4],
       [  2,   8, 300,  -5],
       [  2,   8, 300,  -4],
       [  2,   8, 400,  -5],
       [  2,   8, 400,  -4],
       [  3,   4, 100,  -5],
       [  3,   4, 100,  -4],
       [  3,   4, 200,  -5],
       [  3,   4, 200,  -4],
       [  3,   4, 300,  -5],
       [  3,   4, 300,  -4],
       [  3,   4, 400,  -5],
       [  3,   4, 400,  -4],
       [  3,   8, 100,  -5],
       [  3,   8, 100,  -4],
       [  3,   8, 200,  -5],
       [  3,   8, 200,  -4],
       [  3,   8, 300,  -5],
       [  3,   8, 300,  -4],
       [  3,   8, 400,  -5],
       [  3,   8, 400,  -4]])

If you want to change the first axis fastest (“FORTRAN style” or “column-major”), just change the order parameter of reshape() like this: reshape((-1, N), order='F')


回答 9

熊猫merge提供了一个天真的,快速的解决方案:

# given the lists
x, y, z = [1, 2, 3], [4, 5], [6, 7]

# get dfs with same, constant index 
x = pd.DataFrame({'x': x}, index=np.repeat(0, len(x))
y = pd.DataFrame({'y': y}, index=np.repeat(0, len(y))
z = pd.DataFrame({'z': z}, index=np.repeat(0, len(z))

# get all permutations stored in a new df
df = pd.merge(x, pd.merge(y, z, left_index=True, righ_index=True),
              left_index=True, right_index=True)

Pandas merge offers a naive, fast solution to the problem:

# given the lists
x, y, z = [1, 2, 3], [4, 5], [6, 7]

# get dfs with same, constant index 
x = pd.DataFrame({'x': x}, index=np.repeat(0, len(x))
y = pd.DataFrame({'y': y}, index=np.repeat(0, len(y))
z = pd.DataFrame({'z': z}, index=np.repeat(0, len(z))

# get all permutations stored in a new df
df = pd.merge(x, pd.merge(y, z, left_index=True, righ_index=True),
              left_index=True, right_index=True)

Python中的矩阵转置

问题:Python中的矩阵转置

我正在尝试为python创建矩阵转置函数,但似乎无法使其工作。说我有

theArray = [['a','b','c'],['d','e','f'],['g','h','i']]

我想提出我的职能

newArray = [['a','d','g'],['b','e','h'],['c', 'f', 'i']]

因此,换句话说,如果我要将此2D数组打印为列和行,我希望将行变成列,将列变成行。

我到目前为止已经做到了,但是没有用

def matrixTranspose(anArray):
    transposed = [None]*len(anArray[0])
    for t in range(len(anArray)):
        for tt in range(len(anArray[t])):
            transposed[t] = [None]*len(anArray)
            transposed[t][tt] = anArray[tt][t]
    print transposed

I am trying to create a matrix transpose function for python but I can’t seem to make it work. Say I have

theArray = [['a','b','c'],['d','e','f'],['g','h','i']]

and I want my function to come up with

newArray = [['a','d','g'],['b','e','h'],['c', 'f', 'i']]

So in other words, if I were to print this 2D array as columns and rows I would like the rows to turn into columns and columns into rows.

I made this so far but it doesn’t work

def matrixTranspose(anArray):
    transposed = [None]*len(anArray[0])
    for t in range(len(anArray)):
        for tt in range(len(anArray[t])):
            transposed[t] = [None]*len(anArray)
            transposed[t][tt] = anArray[tt][t]
    print transposed

回答 0

Python 2:

>>> theArray = [['a','b','c'],['d','e','f'],['g','h','i']]
>>> zip(*theArray)
[('a', 'd', 'g'), ('b', 'e', 'h'), ('c', 'f', 'i')]

Python 3:

>>> [*zip(*theArray)]
[('a', 'd', 'g'), ('b', 'e', 'h'), ('c', 'f', 'i')]

Python 2:

>>> theArray = [['a','b','c'],['d','e','f'],['g','h','i']]
>>> zip(*theArray)
[('a', 'd', 'g'), ('b', 'e', 'h'), ('c', 'f', 'i')]

Python 3:

>>> [*zip(*theArray)]
[('a', 'd', 'g'), ('b', 'e', 'h'), ('c', 'f', 'i')]

回答 1

>>> theArray = [['a','b','c'],['d','e','f'],['g','h','i']]
>>> [list(i) for i in zip(*theArray)]
[['a', 'd', 'g'], ['b', 'e', 'h'], ['c', 'f', 'i']]

列表生成器使用列表项而不是元组创建一个新的2d数组。

>>> theArray = [['a','b','c'],['d','e','f'],['g','h','i']]
>>> [list(i) for i in zip(*theArray)]
[['a', 'd', 'g'], ['b', 'e', 'h'], ['c', 'f', 'i']]

the list generator creates a new 2d array with list items instead of tuples.


回答 2

如果行数不相等,也可以使用map

>>> uneven = [['a','b','c'],['d','e'],['g','h','i']]
>>> map(None,*uneven)
[('a', 'd', 'g'), ('b', 'e', 'h'), ('c', None, 'i')]

编辑:在Python 3中mapitertools.zip_longest可以改用已更改的功能:
来源:Python 3.0中的新增功能

>>> import itertools
>>> uneven = [['a','b','c'],['d','e'],['g','h','i']]
>>> list(itertools.zip_longest(*uneven))
[('a', 'd', 'g'), ('b', 'e', 'h'), ('c', None, 'i')]

If your rows are not equal you can also use map:

>>> uneven = [['a','b','c'],['d','e'],['g','h','i']]
>>> map(None,*uneven)
[('a', 'd', 'g'), ('b', 'e', 'h'), ('c', None, 'i')]

Edit: In Python 3 the functionality of map changed, itertools.zip_longest can be used instead:
Source: What’s New In Python 3.0

>>> import itertools
>>> uneven = [['a','b','c'],['d','e'],['g','h','i']]
>>> list(itertools.zip_longest(*uneven))
[('a', 'd', 'g'), ('b', 'e', 'h'), ('c', None, 'i')]

回答 3

使用numpy容易得多:

>>> arr = np.array([[1,2,3],[4,5,6],[7,8,9]])
>>> arr
array([[1, 2, 3],
       [4, 5, 6],
       [7, 8, 9]])
>>> arr.T
array([[1, 4, 7],
       [2, 5, 8],
       [3, 6, 9]])
>>> theArray = np.array([['a','b','c'],['d','e','f'],['g','h','i']])
>>> theArray 
array([['a', 'b', 'c'],
       ['d', 'e', 'f'],
       ['g', 'h', 'i']], 
      dtype='|S1')
>>> theArray.T
array([['a', 'd', 'g'],
       ['b', 'e', 'h'],
       ['c', 'f', 'i']], 
      dtype='|S1')

Much easier with numpy:

>>> arr = np.array([[1,2,3],[4,5,6],[7,8,9]])
>>> arr
array([[1, 2, 3],
       [4, 5, 6],
       [7, 8, 9]])
>>> arr.T
array([[1, 4, 7],
       [2, 5, 8],
       [3, 6, 9]])
>>> theArray = np.array([['a','b','c'],['d','e','f'],['g','h','i']])
>>> theArray 
array([['a', 'b', 'c'],
       ['d', 'e', 'f'],
       ['g', 'h', 'i']], 
      dtype='|S1')
>>> theArray.T
array([['a', 'd', 'g'],
       ['b', 'e', 'h'],
       ['c', 'f', 'i']], 
      dtype='|S1')

回答 4

原始代码的问题在于,您transpose[t]在每个元素上都进行了初始化,而不是每行只初始化一次:

def matrixTranspose(anArray):
    transposed = [None]*len(anArray[0])
    for t in range(len(anArray)):
        transposed[t] = [None]*len(anArray)
        for tt in range(len(anArray[t])):
            transposed[t][tt] = anArray[tt][t]
    print transposed

尽管有更多的Python方式可以完成相同的工作,包括@JF的zip应用程序,但这种方法仍然有效。

The problem with your original code was that you initialized transpose[t] at every element, rather than just once per row:

def matrixTranspose(anArray):
    transposed = [None]*len(anArray[0])
    for t in range(len(anArray)):
        transposed[t] = [None]*len(anArray)
        for tt in range(len(anArray[t])):
            transposed[t][tt] = anArray[tt][t]
    print transposed

This works, though there are more Pythonic ways to accomplish the same things, including @J.F.’s zip application.


回答 5

要完成JF Sebastian的答案,如果您有长度不一的列表,请查看ActiveState上的出色文章。简而言之:

内置函数zip可以执行类似的工作,但是会将结果截断为最短列表的长度,因此之后原始数据中的某些元素可能会丢失。

要处理具有不同长度的列表,请使用:

def transposed(lists):
   if not lists: return []
   return map(lambda *row: list(row), *lists)

def transposed2(lists, defval=0):
   if not lists: return []
   return map(lambda *row: [elem or defval for elem in row], *lists)

To complete J.F. Sebastian’s answer, if you have a list of lists with different lengths, check out this great post from ActiveState. In short:

The built-in function zip does a similar job, but truncates the result to the length of the shortest list, so some elements from the original data may be lost afterwards.

To handle list of lists with different lengths, use:

def transposed(lists):
   if not lists: return []
   return map(lambda *row: list(row), *lists)

def transposed2(lists, defval=0):
   if not lists: return []
   return map(lambda *row: [elem or defval for elem in row], *lists)

回答 6

“最佳”答案已经提交,但是我想我要补充一下,您可以使用嵌套列表推导,如Python教程中所示

这是获取转置数组的方法:

def matrixTranspose( matrix ):
    if not matrix: return []
    return [ [ row[ i ] for row in matrix ] for i in range( len( matrix[ 0 ] ) ) ]

The “best” answer has already been submitted, but I thought I would add that you can use nested list comprehensions, as seen in the Python Tutorial.

Here is how you could get a transposed array:

def matrixTranspose( matrix ):
    if not matrix: return []
    return [ [ row[ i ] for row in matrix ] for i in range( len( matrix[ 0 ] ) ) ]

回答 7

这将保留矩形形状,以便随后的转置将获得正确的结果:

import itertools
def transpose(list_of_lists):
  return list(itertools.izip_longest(*list_of_lists,fillvalue=' '))

This one will preserve rectangular shape, so that subsequent transposes will get the right result:

import itertools
def transpose(list_of_lists):
  return list(itertools.izip_longest(*list_of_lists,fillvalue=' '))

回答 8

您可以像下面这样使用列表理解来尝试

matrix = [['a','b','c'],['d','e','f'],['g','h','i']] n = len(matrix) transpose = [[row[i] for row in matrix] for i in range(n)] print (transpose)

you can try this with list comprehension like the following

matrix = [['a','b','c'],['d','e','f'],['g','h','i']] n = len(matrix) transpose = [[row[i] for row in matrix] for i in range(n)] print (transpose)


回答 9

如果要转置像A = np.array([[1,2 ,, [3,4]])这样的矩阵,则可以简单地使用AT,但是对于像a = [1,2],aT的向量不返回移调!并且您需要使用a.reshape(-1,1),如下所示

import numpy as np
a = np.array([1,2])
print('a.T not transposing Python!\n','a = ',a,'\n','a.T = ', a.T)
print('Transpose of vector a is: \n',a.reshape(-1, 1))

A = np.array([[1,2],[3,4]])
print('Transpose of matrix A is: \n',A.T)

If you want to transpose a matrix like A = np.array([[1,2],[3,4]]), then you can simply use A.T, but for a vector like a = [1,2], a.T does not return a transpose! and you need to use a.reshape(-1, 1), as below

import numpy as np
a = np.array([1,2])
print('a.T not transposing Python!\n','a = ',a,'\n','a.T = ', a.T)
print('Transpose of vector a is: \n',a.reshape(-1, 1))

A = np.array([[1,2],[3,4]])
print('Transpose of matrix A is: \n',A.T)

回答 10

您可以简单地使用python理解来做到这一点。

arr = [
    ['a', 'b', 'c'], 
    ['d', 'e', 'f'], 
    ['g', 'h', 'i']
]
transpose = [[arr[y][x] for y in range(len(arr))] for x in range(len(arr[0]))]

You may do it simply using python comprehension.

arr = [
    ['a', 'b', 'c'], 
    ['d', 'e', 'f'], 
    ['g', 'h', 'i']
]
transpose = [[arr[y][x] for y in range(len(arr))] for x in range(len(arr[0]))]

回答 11

def matrixTranspose(anArray):
  transposed = [None]*len(anArray[0])

  for i in range(len(transposed)):
    transposed[i] = [None]*len(transposed)

  for t in range(len(anArray)):
    for tt in range(len(anArray[t])):            
        transposed[t][tt] = anArray[tt][t]
  return transposed

theArray = [['a','b','c'],['d','e','f'],['g','h','i']]

print matrixTranspose(theArray)
def matrixTranspose(anArray):
  transposed = [None]*len(anArray[0])

  for i in range(len(transposed)):
    transposed[i] = [None]*len(transposed)

  for t in range(len(anArray)):
    for tt in range(len(anArray[t])):            
        transposed[t][tt] = anArray[tt][t]
  return transposed

theArray = [['a','b','c'],['d','e','f'],['g','h','i']]

print matrixTranspose(theArray)

回答 12

#generate matrix
matrix=[]
m=input('enter number of rows, m = ')
n=input('enter number of columns, n = ')
for i in range(m):
    matrix.append([])
    for j in range(n):
        elem=input('enter element: ')
        matrix[i].append(elem)

#print matrix
for i in range(m):
    for j in range(n):
        print matrix[i][j],
    print '\n'

#generate transpose
transpose=[]
for j in range(n):
    transpose.append([])
    for i in range (m):
        ent=matrix[i][j]
        transpose[j].append(ent)

#print transpose
for i in range (n):
    for j in range (m):
        print transpose[i][j],
    print '\n'
#generate matrix
matrix=[]
m=input('enter number of rows, m = ')
n=input('enter number of columns, n = ')
for i in range(m):
    matrix.append([])
    for j in range(n):
        elem=input('enter element: ')
        matrix[i].append(elem)

#print matrix
for i in range(m):
    for j in range(n):
        print matrix[i][j],
    print '\n'

#generate transpose
transpose=[]
for j in range(n):
    transpose.append([])
    for i in range (m):
        ent=matrix[i][j]
        transpose[j].append(ent)

#print transpose
for i in range (n):
    for j in range (m):
        print transpose[i][j],
    print '\n'

回答 13

a=[]
def showmatrix (a,m,n):
    for i in range (m):
        for j in range (n):
            k=int(input("enter the number")
            a.append(k)      
print (a[i][j]),

print('\t')


def showtranspose(a,m,n):
    for j in range(n):
        for i in range(m):
            print(a[i][j]),
        print('\t')

a=((89,45,50),(130,120,40),(69,79,57),(78,4,8))
print("given matrix of order 4x3 is :")
showmatrix(a,4,3)


print("Transpose matrix is:")
showtranspose(a,4,3)
a=[]
def showmatrix (a,m,n):
    for i in range (m):
        for j in range (n):
            k=int(input("enter the number")
            a.append(k)      
print (a[i][j]),

print('\t')


def showtranspose(a,m,n):
    for j in range(n):
        for i in range(m):
            print(a[i][j]),
        print('\t')

a=((89,45,50),(130,120,40),(69,79,57),(78,4,8))
print("given matrix of order 4x3 is :")
showmatrix(a,4,3)


print("Transpose matrix is:")
showtranspose(a,4,3)

回答 14

def transpose(matrix):
   x=0
   trans=[]
   b=len(matrix[0])
   while b!=0:
       trans.append([])
       b-=1
   for list in matrix:
       for element in list:
          trans[x].append(element)
          x+=1
       x=0
   return trans
def transpose(matrix):
   x=0
   trans=[]
   b=len(matrix[0])
   while b!=0:
       trans.append([])
       b-=1
   for list in matrix:
       for element in list:
          trans[x].append(element)
          x+=1
       x=0
   return trans

回答 15

def transpose(matrix):
    listOfLists = []
    for row in range(len(matrix[0])):
        colList = []
        for col in range(len(matrix)):
            colList.append(matrix[col][row])
    listOfLists.append(colList)

    return listOfLists
def transpose(matrix):
    listOfLists = []
    for row in range(len(matrix[0])):
        colList = []
        for col in range(len(matrix)):
            colList.append(matrix[col][row])
    listOfLists.append(colList)

    return listOfLists

回答 16

`

def transpose(m):
    return(list(map(list,list(zip(*m)))))

`此函数将返回转置

`

def transpose(m):
    return(list(map(list,list(zip(*m)))))

`This function will return the transpose


回答 17

Python程式转置矩阵:

row,col = map(int,input().split())
matrix = list()

for i in range(row):
    r = list(map(int,input().split()))
    matrix.append(r)

trans = [[0 for y in range(row)]for x in range(col)]

for i in range(len(matrix[0])):
    for j in range(len(matrix)):
        trans[i][j] = matrix[j][i]     

for i in range(len(trans)):
    for j in range(len(trans[0])):
        print(trans[i][j],end=' ')
    print(' ')

Python Program to transpose matrix:

row,col = map(int,input().split())
matrix = list()

for i in range(row):
    r = list(map(int,input().split()))
    matrix.append(r)

trans = [[0 for y in range(row)]for x in range(col)]

for i in range(len(matrix[0])):
    for j in range(len(matrix)):
        trans[i][j] = matrix[j][i]     

for i in range(len(trans)):
    for j in range(len(trans[0])):
        print(trans[i][j],end=' ')
    print(' ')

了解NumPy的einsum

问题:了解NumPy的einsum

我正在努力了解确切的einsum工作原理。我看了一下文档和一些示例,但看起来似乎并不固定。

这是我们在课堂上讲的一个例子:

C = np.einsum("ij,jk->ki", A, B)

对于两个数组AB

我认为可以A^T * B,但是我不确定(正在对其中之一进行移调吗?)。谁能告诉我这里到底发生了什么(以及使用时的一般情况einsum)?

I’m struggling to understand exactly how einsum works. I’ve looked at the documentation and a few examples, but it’s not seeming to stick.

Here’s an example we went over in class:

C = np.einsum("ij,jk->ki", A, B)

for two arraysA and B

I think this would take A^T * B, but I’m not sure (it’s taking the transpose of one of them right?). Can anyone walk me through exactly what’s happening here (and in general when using einsum)?


回答 0

(注:这个答案是基于短的博客文章einsum我写了前一阵子。)

怎么einsum办?

假设我们有两个多维数组,AB。现在假设我们要…

  • AB一种特殊的方式来创造新的产品阵列; 然后也许
  • 沿特定轴求和该新数组;然后也许
  • 以特定顺序转置新数组的轴。

有一个很好的机会,einsum可以帮助我们做到这一点更快,内存更是有效的NumPy的功能组合,喜欢multiplysumtranspose允许。

einsum工作如何?

这是一个简单(但并非完全无关紧要)的示例。取以下两个数组:

A = np.array([0, 1, 2])

B = np.array([[ 0,  1,  2,  3],
              [ 4,  5,  6,  7],
              [ 8,  9, 10, 11]])

我们将逐个元素相乘AB然后沿着新数组的行求和。在“普通” NumPy中,我们将编写:

>>> (A[:, np.newaxis] * B).sum(axis=1)
array([ 0, 22, 76])

因此,此处的索引操作A将两个数组的第一个轴对齐,以便可以广播乘法。然后将乘积数组中的行相加以返回答案。

现在,如果我们想使用它einsum,我们可以这样写:

>>> np.einsum('i,ij->i', A, B)
array([ 0, 22, 76])

签名字符串'i,ij->i'是这里的关键,需要解释的一点。您可以将其分为两半。在左侧(的左侧->),我们标记了两个输入数组。在的右侧->,我们标记了要结束的数组。

接下来会发生以下情况:

  • A有一个轴 我们已经标记了它i。并且B有两个轴;我们将轴0标记为i,将轴1 标记为j

  • 通过在两个输入数组中重复标签i,我们告诉我们einsum这两个轴应该相乘。换句话说,就像A数组B一样,我们将array 与array 的每一列相乘A[:, np.newaxis] * B

  • 请注意,j它不会在所需的输出中显示为标签;我们刚刚使用过i(我们想以一维数组结尾)。通过省略标签,我们告诉einsum总结沿着这条轴线。换句话说,我们就像对行进行求和.sum(axis=1)

基本上,这是您需要了解的所有信息einsum。玩一会会有所帮助;如果我们将两个标签都留在输出中,则会'i,ij->ij'返回2D产品数组(与相同A[:, np.newaxis] * B)。如果我们说没有输出标签,'i,ij->我们将返回一个数字(与相同(A[:, np.newaxis] * B).sum())。

einsum但是,最重要的是,它不会首先构建临时产品系列;它只是对产品进行累加。这样可以节省大量内存。

一个更大的例子

为了解释点积,这里有两个新数组:

A = array([[1, 1, 1],
           [2, 2, 2],
           [5, 5, 5]])

B = array([[0, 1, 0],
           [1, 1, 0],
           [1, 1, 1]])

我们将使用计算点积np.einsum('ij,jk->ik', A, B)。这是一张图片,显示了从函数获得的AB和输出数组的标签:

您会看到j重复的标签-这意味着我们会将的行A与的列相乘B。此外,j输出中不包含标签-我们对这些产品进行求和。标签ik被保留用于输出,因此我们得到一个2D数组。

这一结果与其中标签阵列比较可能是更加明显j求和。在下面的左侧,您可以看到写入产生的3D数组np.einsum('ij,jk->ijk', A, B)(即,我们保留了label j):

求和轴j给出了预期的点积,如右图所示。

一些练习

为了获得更多的感觉einsum,使用下标符号实现熟悉的NumPy数组操作可能会很有用。任何涉及乘法和求和轴组合的内容都可以使用编写 einsum

令A和B为两个具有相同长度的一维数组。例如A = np.arange(10)B = np.arange(5, 15)

  • 的总和A可以写成:

    np.einsum('i->', A)
  • A * B可以按元素写成:

    np.einsum('i,i->i', A, B)
  • 内积或点积np.inner(A, B)np.dot(A, B)可以写成:

    np.einsum('i,i->', A, B) # or just use 'i,i'
  • 外部乘积np.outer(A, B)可以写成:

    np.einsum('i,j->ij', A, B)

对于2D数组,CD,只要轴是兼容的长度(相同长度或其中之一具有长度1),下面是一些示例:

  • C(主对角线总和)的轨迹np.trace(C)可以写成:

    np.einsum('ii', C)
  • 的元素方式乘法C和转置DC * D.T可以写成:

    np.einsum('ij,ji->ij', C, D)
  • 可以将每个元素乘以C该数组D(以构成4D数组)C[:, :, None, None] * D,可以写成:

    np.einsum('ij,kl->ijkl', C, D)  

(Note: this answer is based on a short blog post about einsum I wrote a while ago.)

What does einsum do?

Imagine that we have two multi-dimensional arrays, A and B. Now let’s suppose we want to…

  • multiply A with B in a particular way to create new array of products; and then maybe
  • sum this new array along particular axes; and then maybe
  • transpose the axes of the new array in a particular order.

There’s a good chance that einsum will help us do this faster and more memory-efficiently that combinations of the NumPy functions like multiply, sum and transpose will allow.

How does einsum work?

Here’s a simple (but not completely trivial) example. Take the following two arrays:

A = np.array([0, 1, 2])

B = np.array([[ 0,  1,  2,  3],
              [ 4,  5,  6,  7],
              [ 8,  9, 10, 11]])

We will multiply A and B element-wise and then sum along the rows of the new array. In “normal” NumPy we’d write:

>>> (A[:, np.newaxis] * B).sum(axis=1)
array([ 0, 22, 76])

So here, the indexing operation on A lines up the first axes of the two arrays so that the multiplication can be broadcast. The rows of the array of products is then summed to return the answer.

Now if we wanted to use einsum instead, we could write:

>>> np.einsum('i,ij->i', A, B)
array([ 0, 22, 76])

The signature string 'i,ij->i' is the key here and needs a little bit of explaining. You can think of it in two halves. On the left-hand side (left of the ->) we’ve labelled the two input arrays. To the right of ->, we’ve labelled the array we want to end up with.

Here is what happens next:

  • A has one axis; we’ve labelled it i. And B has two axes; we’ve labelled axis 0 as i and axis 1 as j.

  • By repeating the label i in both input arrays, we are telling einsum that these two axes should be multiplied together. In other words, we’re multiplying array A with each column of array B, just like A[:, np.newaxis] * B does.

  • Notice that j does not appear as a label in our desired output; we’ve just used i (we want to end up with a 1D array). By omitting the label, we’re telling einsum to sum along this axis. In other words, we’re summing the rows of the products, just like .sum(axis=1) does.

That’s basically all you need to know to use einsum. It helps to play about a little; if we leave both labels in the output, 'i,ij->ij', we get back a 2D array of products (same as A[:, np.newaxis] * B). If we say no output labels, 'i,ij->, we get back a single number (same as doing (A[:, np.newaxis] * B).sum()).

The great thing about einsum however, is that is does not build a temporary array of products first; it just sums the products as it goes. This can lead to big savings in memory use.

A slightly bigger example

To explain the dot product, here are two new arrays:

A = array([[1, 1, 1],
           [2, 2, 2],
           [5, 5, 5]])

B = array([[0, 1, 0],
           [1, 1, 0],
           [1, 1, 1]])

We will compute the dot product using np.einsum('ij,jk->ik', A, B). Here’s a picture showing the labelling of the A and B and the output array that we get from the function:

You can see that label j is repeated – this means we’re multiplying the rows of A with the columns of B. Furthermore, the label j is not included in the output – we’re summing these products. Labels i and k are kept for the output, so we get back a 2D array.

It might be even clearer to compare this result with the array where the label j is not summed. Below, on the left you can see the 3D array that results from writing np.einsum('ij,jk->ijk', A, B) (i.e. we’ve kept label j):

Summing axis j gives the expected dot product, shown on the right.

Some exercises

To get more of feel for einsum, it can be useful to implement familiar NumPy array operations using the subscript notation. Anything that involves combinations of multiplying and summing axes can be written using einsum.

Let A and B be two 1D arrays with the same length. For example, A = np.arange(10) and B = np.arange(5, 15).

  • The sum of A can be written:

    np.einsum('i->', A)
    
  • Element-wise multiplication, A * B, can be written:

    np.einsum('i,i->i', A, B)
    
  • The inner product or dot product, np.inner(A, B) or np.dot(A, B), can be written:

    np.einsum('i,i->', A, B) # or just use 'i,i'
    
  • The outer product, np.outer(A, B), can be written:

    np.einsum('i,j->ij', A, B)
    

For 2D arrays, C and D, provided that the axes are compatible lengths (both the same length or one of them of has length 1), here are a few examples:

  • The trace of C (sum of main diagonal), np.trace(C), can be written:

    np.einsum('ii', C)
    
  • Element-wise multiplication of C and the transpose of D, C * D.T, can be written:

    np.einsum('ij,ji->ij', C, D)
    
  • Multiplying each element of C by the array D (to make a 4D array), C[:, :, None, None] * D, can be written:

    np.einsum('ij,kl->ijkl', C, D)  
    

回答 1

numpy.einsum()如果您直观地理解它的想法,将非常容易。作为示例,让我们从涉及矩阵乘法的简单描述开始。


使用时numpy.einsum(),您要做的就是传递所谓的下标字符串作为参数,然后传递输入数组

假设您有两个2D数组AB,并且想要进行矩阵乘法。所以你也是:

np.einsum("ij, jk -> ik", A, B)

在这里,下标字符串 ij对应于array,A下标字符串 jk对应于array B。另外,这里要注意的最重要的一点是,每个下标字符串中的字符数必须与数组的大小匹配。(例如,对于2D数组为2个字符,对于3D数组为3个字符,依此类推。)如果您在下标字符串之间重复字符(在我们的示例中),则意味着您希望总和沿着这些维度发生。因此,它们将减少总和。(即该维度将消失 jein

此之后的下标字符串->将成为我们的结果数组。如果将其保留为空,则将对所有内容求和,并返回标量值作为结果。否则,所得数组将具有根据下标字符串的尺寸。在我们的示例中,它将为ik。这很直观,因为我们知道对于矩阵乘法,数组中的列数A必须与数组中的行数相匹配,B这就是这里发生的情况(即,我们通过在下标字符串中重复char j来编码此知识)


这里还有一些其他示例,简要说明了np.einsum()实现某些常见张量nd数组操作的用途/功能。

输入项

# a vector
In [197]: vec
Out[197]: array([0, 1, 2, 3])

# an array
In [198]: A
Out[198]: 
array([[11, 12, 13, 14],
       [21, 22, 23, 24],
       [31, 32, 33, 34],
       [41, 42, 43, 44]])

# another array
In [199]: B
Out[199]: 
array([[1, 1, 1, 1],
       [2, 2, 2, 2],
       [3, 3, 3, 3],
       [4, 4, 4, 4]])

1)矩阵乘法(类似于np.matmul(arr1, arr2)

In [200]: np.einsum("ij, jk -> ik", A, B)
Out[200]: 
array([[130, 130, 130, 130],
       [230, 230, 230, 230],
       [330, 330, 330, 330],
       [430, 430, 430, 430]])

2)沿主对角线提取元素(类似于np.diag(arr)

In [202]: np.einsum("ii -> i", A)
Out[202]: array([11, 22, 33, 44])

3)Hadamard乘积(即两个数组的按元素乘积)(类似于arr1 * arr2

In [203]: np.einsum("ij, ij -> ij", A, B)
Out[203]: 
array([[ 11,  12,  13,  14],
       [ 42,  44,  46,  48],
       [ 93,  96,  99, 102],
       [164, 168, 172, 176]])

4)逐元素平方(类似于np.square(arr)arr ** 2

In [210]: np.einsum("ij, ij -> ij", B, B)
Out[210]: 
array([[ 1,  1,  1,  1],
       [ 4,  4,  4,  4],
       [ 9,  9,  9,  9],
       [16, 16, 16, 16]])

5)痕迹(即主对角元素的总和)(类似于np.trace(arr)

In [217]: np.einsum("ii -> ", A)
Out[217]: 110

6)矩阵转置(类似于np.transpose(arr)

In [221]: np.einsum("ij -> ji", A)
Out[221]: 
array([[11, 21, 31, 41],
       [12, 22, 32, 42],
       [13, 23, 33, 43],
       [14, 24, 34, 44]])

7)(向量的)外积(类似于np.outer(vec1, vec2)

In [255]: np.einsum("i, j -> ij", vec, vec)
Out[255]: 
array([[0, 0, 0, 0],
       [0, 1, 2, 3],
       [0, 2, 4, 6],
       [0, 3, 6, 9]])

8)(向量的)内积(类似于np.inner(vec1, vec2)

In [256]: np.einsum("i, i -> ", vec, vec)
Out[256]: 14

9)沿轴0求和(类似于np.sum(arr, axis=0)

In [260]: np.einsum("ij -> j", B)
Out[260]: array([10, 10, 10, 10])

10)沿轴1的总和(类似于np.sum(arr, axis=1)

In [261]: np.einsum("ij -> i", B)
Out[261]: array([ 4,  8, 12, 16])

11)批矩阵乘法

In [287]: BM = np.stack((A, B), axis=0)

In [288]: BM
Out[288]: 
array([[[11, 12, 13, 14],
        [21, 22, 23, 24],
        [31, 32, 33, 34],
        [41, 42, 43, 44]],

       [[ 1,  1,  1,  1],
        [ 2,  2,  2,  2],
        [ 3,  3,  3,  3],
        [ 4,  4,  4,  4]]])

In [289]: BM.shape
Out[289]: (2, 4, 4)

# batch matrix multiply using einsum
In [292]: BMM = np.einsum("bij, bjk -> bik", BM, BM)

In [293]: BMM
Out[293]: 
array([[[1350, 1400, 1450, 1500],
        [2390, 2480, 2570, 2660],
        [3430, 3560, 3690, 3820],
        [4470, 4640, 4810, 4980]],

       [[  10,   10,   10,   10],
        [  20,   20,   20,   20],
        [  30,   30,   30,   30],
        [  40,   40,   40,   40]]])

In [294]: BMM.shape
Out[294]: (2, 4, 4)

12)沿轴2的总和(类似于np.sum(arr, axis=2)

In [330]: np.einsum("ijk -> ij", BM)
Out[330]: 
array([[ 50,  90, 130, 170],
       [  4,   8,  12,  16]])

13)对数组中的所有元素求和(类似于np.sum(arr)

In [335]: np.einsum("ijk -> ", BM)
Out[335]: 480

14)多轴总和(即边际化)
(类似于np.sum(arr, axis=(axis0, axis1, axis2, axis3, axis4, axis6, axis7))

# 8D array
In [354]: R = np.random.standard_normal((3,5,4,6,8,2,7,9))

# marginalize out axis 5 (i.e. "n" here)
In [363]: esum = np.einsum("ijklmnop -> n", R)

# marginalize out axis 5 (i.e. sum over rest of the axes)
In [364]: nsum = np.sum(R, axis=(0,1,2,3,4,6,7))

In [365]: np.allclose(esum, nsum)
Out[365]: True

15)双点(类似于np.sum(哈达玛积) cf. 3

In [772]: A
Out[772]: 
array([[1, 2, 3],
       [4, 2, 2],
       [2, 3, 4]])

In [773]: B
Out[773]: 
array([[1, 4, 7],
       [2, 5, 8],
       [3, 6, 9]])

In [774]: np.einsum("ij, ij -> ", A, B)
Out[774]: 124

16)2D和3D阵列乘法

在要验证结果的线性方程组(Ax = b)求解时,这种乘法可能非常有用。

# inputs
In [115]: A = np.random.rand(3,3)
In [116]: b = np.random.rand(3, 4, 5)

# solve for x
In [117]: x = np.linalg.solve(A, b.reshape(b.shape[0], -1)).reshape(b.shape)

# 2D and 3D array multiplication :)
In [118]: Ax = np.einsum('ij, jkl', A, x)

# indeed the same!
In [119]: np.allclose(Ax, b)
Out[119]: True

相反,如果必须使用np.matmul()此验证,则我们必须执行几项reshape操作才能获得相同的结果,例如:

# reshape 3D array `x` to 2D, perform matmul
# then reshape the resultant array to 3D
In [123]: Ax_matmul = np.matmul(A, x.reshape(x.shape[0], -1)).reshape(x.shape)

# indeed correct!
In [124]: np.allclose(Ax, Ax_matmul)
Out[124]: True

奖金:在这里阅读更多数学:爱因斯坦求和,当然在这里:张量表示法

Grasping the idea of numpy.einsum() is very easy if you understand it intuitively. As an example, let’s start with a simple description involving matrix multiplication.


To use numpy.einsum(), all you have to do is to pass the so-called subscripts string as an argument, followed by your input arrays.

Let’s say you have two 2D arrays, A and B, and you want to do matrix multiplication. So, you do:

np.einsum("ij, jk -> ik", A, B)

Here the subscript string ij corresponds to array A while the subscript string jk corresponds to array B. Also, the most important thing to note here is that the number of characters in each subscript string must match the dimensions of the array. (i.e. two chars for 2D arrays, three chars for 3D arrays, and so on.) And if you repeat the chars between subscript strings (j in our case), then that means you want the einsum to happen along those dimensions. Thus, they will be sum-reduced. (i.e. that dimension will be gone)

The subscript string after this ->, will be our resultant array. If you leave it empty, then everything will be summed and a scalar value is returned as result. Else the resultant array will have dimensions according to the subscript string. In our example, it’ll be ik. This is intuitive because we know that for matrix multiplication the number of columns in array A has to match the number of rows in array B which is what is happening here (i.e. we encode this knowledge by repeating the char j in the subscript string)


Here are some more examples illustrating the use/power of np.einsum() in implementing some common tensor or nd-array operations, succinctly.

Inputs

# a vector
In [197]: vec
Out[197]: array([0, 1, 2, 3])

# an array
In [198]: A
Out[198]: 
array([[11, 12, 13, 14],
       [21, 22, 23, 24],
       [31, 32, 33, 34],
       [41, 42, 43, 44]])

# another array
In [199]: B
Out[199]: 
array([[1, 1, 1, 1],
       [2, 2, 2, 2],
       [3, 3, 3, 3],
       [4, 4, 4, 4]])

1) Matrix multiplication (similar to np.matmul(arr1, arr2))

In [200]: np.einsum("ij, jk -> ik", A, B)
Out[200]: 
array([[130, 130, 130, 130],
       [230, 230, 230, 230],
       [330, 330, 330, 330],
       [430, 430, 430, 430]])

2) Extract elements along the main-diagonal (similar to np.diag(arr))

In [202]: np.einsum("ii -> i", A)
Out[202]: array([11, 22, 33, 44])

3) Hadamard product (i.e. element-wise product of two arrays) (similar to arr1 * arr2)

In [203]: np.einsum("ij, ij -> ij", A, B)
Out[203]: 
array([[ 11,  12,  13,  14],
       [ 42,  44,  46,  48],
       [ 93,  96,  99, 102],
       [164, 168, 172, 176]])

4) Element-wise squaring (similar to np.square(arr) or arr ** 2)

In [210]: np.einsum("ij, ij -> ij", B, B)
Out[210]: 
array([[ 1,  1,  1,  1],
       [ 4,  4,  4,  4],
       [ 9,  9,  9,  9],
       [16, 16, 16, 16]])

5) Trace (i.e. sum of main-diagonal elements) (similar to np.trace(arr))

In [217]: np.einsum("ii -> ", A)
Out[217]: 110

6) Matrix transpose (similar to np.transpose(arr))

In [221]: np.einsum("ij -> ji", A)
Out[221]: 
array([[11, 21, 31, 41],
       [12, 22, 32, 42],
       [13, 23, 33, 43],
       [14, 24, 34, 44]])

7) Outer Product (of vectors) (similar to np.outer(vec1, vec2))

In [255]: np.einsum("i, j -> ij", vec, vec)
Out[255]: 
array([[0, 0, 0, 0],
       [0, 1, 2, 3],
       [0, 2, 4, 6],
       [0, 3, 6, 9]])

8) Inner Product (of vectors) (similar to np.inner(vec1, vec2))

In [256]: np.einsum("i, i -> ", vec, vec)
Out[256]: 14

9) Sum along axis 0 (similar to np.sum(arr, axis=0))

In [260]: np.einsum("ij -> j", B)
Out[260]: array([10, 10, 10, 10])

10) Sum along axis 1 (similar to np.sum(arr, axis=1))

In [261]: np.einsum("ij -> i", B)
Out[261]: array([ 4,  8, 12, 16])

11) Batch Matrix Multiplication

In [287]: BM = np.stack((A, B), axis=0)

In [288]: BM
Out[288]: 
array([[[11, 12, 13, 14],
        [21, 22, 23, 24],
        [31, 32, 33, 34],
        [41, 42, 43, 44]],

       [[ 1,  1,  1,  1],
        [ 2,  2,  2,  2],
        [ 3,  3,  3,  3],
        [ 4,  4,  4,  4]]])

In [289]: BM.shape
Out[289]: (2, 4, 4)

# batch matrix multiply using einsum
In [292]: BMM = np.einsum("bij, bjk -> bik", BM, BM)

In [293]: BMM
Out[293]: 
array([[[1350, 1400, 1450, 1500],
        [2390, 2480, 2570, 2660],
        [3430, 3560, 3690, 3820],
        [4470, 4640, 4810, 4980]],

       [[  10,   10,   10,   10],
        [  20,   20,   20,   20],
        [  30,   30,   30,   30],
        [  40,   40,   40,   40]]])

In [294]: BMM.shape
Out[294]: (2, 4, 4)

12) Sum along axis 2 (similar to np.sum(arr, axis=2))

In [330]: np.einsum("ijk -> ij", BM)
Out[330]: 
array([[ 50,  90, 130, 170],
       [  4,   8,  12,  16]])

13) Sum all the elements in array (similar to np.sum(arr))

In [335]: np.einsum("ijk -> ", BM)
Out[335]: 480

14) Sum over multiple axes (i.e. marginalization)
(similar to np.sum(arr, axis=(axis0, axis1, axis2, axis3, axis4, axis6, axis7)))

# 8D array
In [354]: R = np.random.standard_normal((3,5,4,6,8,2,7,9))

# marginalize out axis 5 (i.e. "n" here)
In [363]: esum = np.einsum("ijklmnop -> n", R)

# marginalize out axis 5 (i.e. sum over rest of the axes)
In [364]: nsum = np.sum(R, axis=(0,1,2,3,4,6,7))

In [365]: np.allclose(esum, nsum)
Out[365]: True

15) Double Dot Products (similar to np.sum(hadamard-product) cf. 3)

In [772]: A
Out[772]: 
array([[1, 2, 3],
       [4, 2, 2],
       [2, 3, 4]])

In [773]: B
Out[773]: 
array([[1, 4, 7],
       [2, 5, 8],
       [3, 6, 9]])

In [774]: np.einsum("ij, ij -> ", A, B)
Out[774]: 124

16) 2D and 3D array multiplication

Such a multiplication could be very useful when solving linear system of equations (Ax = b) where you want to verify the result.

# inputs
In [115]: A = np.random.rand(3,3)
In [116]: b = np.random.rand(3, 4, 5)

# solve for x
In [117]: x = np.linalg.solve(A, b.reshape(b.shape[0], -1)).reshape(b.shape)

# 2D and 3D array multiplication :)
In [118]: Ax = np.einsum('ij, jkl', A, x)

# indeed the same!
In [119]: np.allclose(Ax, b)
Out[119]: True

On the contrary, if one has to use np.matmul() for this verification, we have to do couple of reshape operations to achieve the same result like:

# reshape 3D array `x` to 2D, perform matmul
# then reshape the resultant array to 3D
In [123]: Ax_matmul = np.matmul(A, x.reshape(x.shape[0], -1)).reshape(x.shape)

# indeed correct!
In [124]: np.allclose(Ax, Ax_matmul)
Out[124]: True

Bonus: Read more math here : Einstein-Summation and definitely here: Tensor-Notation


回答 2

让我们制作2个数组,它们具有不同但兼容的维度,以突出它们之间的相互作用

In [43]: A=np.arange(6).reshape(2,3)
Out[43]: 
array([[0, 1, 2],
       [3, 4, 5]])


In [44]: B=np.arange(12).reshape(3,4)
Out[44]: 
array([[ 0,  1,  2,  3],
       [ 4,  5,  6,  7],
       [ 8,  9, 10, 11]])

您的计算将(2,3)的“点”(乘积之和)与(3,4)相乘,以生成(4,2)数组。 i是第一个昏暗的A,最后一个C; k最后B1个,第1个Cj通过求和“消耗”。

In [45]: C=np.einsum('ij,jk->ki',A,B)
Out[45]: 
array([[20, 56],
       [23, 68],
       [26, 80],
       [29, 92]])

这与np.dot(A,B).T-是转置的最终输出相同。

要查看更多情况j,请将C下标更改为ijk

In [46]: np.einsum('ij,jk->ijk',A,B)
Out[46]: 
array([[[ 0,  0,  0,  0],
        [ 4,  5,  6,  7],
        [16, 18, 20, 22]],

       [[ 0,  3,  6,  9],
        [16, 20, 24, 28],
        [40, 45, 50, 55]]])

这也可以通过以下方式生成:

A[:,:,None]*B[None,:,:]

即,添加一个k维度的端部A,以及i与前部B,产生了(2,3,4)阵列。

0 + 4 + 16 = 209 + 28 + 55 = 92等; 求和j转置以获得较早的结果:

np.sum(A[:,:,None] * B[None,:,:], axis=1).T

# C[k,i] = sum(j) A[i,j (,k) ] * B[(i,)  j,k]

Lets make 2 arrays, with different, but compatible dimensions to highlight their interplay

In [43]: A=np.arange(6).reshape(2,3)
Out[43]: 
array([[0, 1, 2],
       [3, 4, 5]])


In [44]: B=np.arange(12).reshape(3,4)
Out[44]: 
array([[ 0,  1,  2,  3],
       [ 4,  5,  6,  7],
       [ 8,  9, 10, 11]])

Your calculation, takes a ‘dot’ (sum of products) of a (2,3) with a (3,4) to produce a (4,2) array. i is the 1st dim of A, the last of C; k the last of B, 1st of C. j is ‘consumed’ by the summation.

In [45]: C=np.einsum('ij,jk->ki',A,B)
Out[45]: 
array([[20, 56],
       [23, 68],
       [26, 80],
       [29, 92]])

This is the same as np.dot(A,B).T – it’s the final output that’s transposed.

To see more of what happens to j, change the C subscripts to ijk:

In [46]: np.einsum('ij,jk->ijk',A,B)
Out[46]: 
array([[[ 0,  0,  0,  0],
        [ 4,  5,  6,  7],
        [16, 18, 20, 22]],

       [[ 0,  3,  6,  9],
        [16, 20, 24, 28],
        [40, 45, 50, 55]]])

This can also be produced with:

A[:,:,None]*B[None,:,:]

That is, add a k dimension to the end of A, and an i to the front of B, resulting in a (2,3,4) array.

0 + 4 + 16 = 20, 9 + 28 + 55 = 92, etc; Sum on j and transpose to get the earlier result:

np.sum(A[:,:,None] * B[None,:,:], axis=1).T

# C[k,i] = sum(j) A[i,j (,k) ] * B[(i,)  j,k]

回答 3

我发现NumPy:交易技巧(第二部分)具有启发性

我们使用->指示输出数组的顺序。因此,将“ ij,i-> j”视为具有左侧(LHS)和右侧(RHS)。LHS上标签的任何重复都会明智地计算乘积元素,然后求和。通过更改RHS(输出)端的标签,我们可以相对于输入数组定义要在其中进行处理的轴,即沿轴0、1求和,依此类推。

import numpy as np

>>> a
array([[1, 1, 1],
       [2, 2, 2],
       [3, 3, 3]])
>>> b
array([[0, 1, 2],
       [3, 4, 5],
       [6, 7, 8]])
>>> d = np.einsum('ij, jk->ki', a, b)

请注意,存在三个轴,即i,j,k,并且重复了j(在左侧)。 i,j代表的行和列aj,kb

为了计算乘积并对齐j轴,我们需要在上添加一个轴a。(b将沿第一个轴广播?)

a[i, j, k]
   b[j, k]

>>> c = a[:,:,np.newaxis] * b
>>> c
array([[[ 0,  1,  2],
        [ 3,  4,  5],
        [ 6,  7,  8]],

       [[ 0,  2,  4],
        [ 6,  8, 10],
        [12, 14, 16]],

       [[ 0,  3,  6],
        [ 9, 12, 15],
        [18, 21, 24]]])

j在右侧不存在,因此我们求和j是3x3x3数组的第二个轴

>>> c = c.sum(1)
>>> c
array([[ 9, 12, 15],
       [18, 24, 30],
       [27, 36, 45]])

最后,索引在右侧(按字母顺序)相反,因此我们进行了转置。

>>> c.T
array([[ 9, 18, 27],
       [12, 24, 36],
       [15, 30, 45]])

>>> np.einsum('ij, jk->ki', a, b)
array([[ 9, 18, 27],
       [12, 24, 36],
       [15, 30, 45]])
>>>

I found NumPy: The tricks of the trade (Part II) instructive

We use -> to indicate the order of the output array. So think of ‘ij, i->j’ as having left hand side (LHS) and right hand side (RHS). Any repetition of labels on the LHS computes the product element wise and then sums over. By changing the label on the RHS (output) side, we can define the axis in which we want to proceed with respect to the input array, i.e. summation along axis 0, 1 and so on.

import numpy as np

>>> a
array([[1, 1, 1],
       [2, 2, 2],
       [3, 3, 3]])
>>> b
array([[0, 1, 2],
       [3, 4, 5],
       [6, 7, 8]])
>>> d = np.einsum('ij, jk->ki', a, b)

Notice there are three axes, i, j, k, and that j is repeated (on the left-hand-side). i,j represent rows and columns for a. j,k for b.

In order to calculate the product and align the j axis we need to add an axis to a. (b will be broadcast along(?) the first axis)

a[i, j, k]
   b[j, k]

>>> c = a[:,:,np.newaxis] * b
>>> c
array([[[ 0,  1,  2],
        [ 3,  4,  5],
        [ 6,  7,  8]],

       [[ 0,  2,  4],
        [ 6,  8, 10],
        [12, 14, 16]],

       [[ 0,  3,  6],
        [ 9, 12, 15],
        [18, 21, 24]]])

j is absent from the right-hand-side so we sum over j which is the second axis of the 3x3x3 array

>>> c = c.sum(1)
>>> c
array([[ 9, 12, 15],
       [18, 24, 30],
       [27, 36, 45]])

Finally, the indices are (alphabetically) reversed on the right-hand-side so we transpose.

>>> c.T
array([[ 9, 18, 27],
       [12, 24, 36],
       [15, 30, 45]])

>>> np.einsum('ij, jk->ki', a, b)
array([[ 9, 18, 27],
       [12, 24, 36],
       [15, 30, 45]])
>>>

回答 4

在阅读einsum方程式时,我发现最简单的方法就是将它们简化为必要的形式。

让我们从以下(强加)语句开始:

C = np.einsum('bhwi,bhwj->bij', A, B)

首先通过标点符号进行操作,我们看到在箭头前有两个4个逗号分隔的斑点- bhwibhwj,在箭头后有一个3个字母斑点bij。因此,该方程从两个4级张量输入产生3级张量结果。

现在,让每个斑点中的每个字母成为范围变量的名称。字母在Blob中出现的位置是该张量范围内的轴的索引。因此,产生C的每个元素的命令式求和必须从三个嵌套的for循环开始,每个C的索引一个。

for b in range(...):
    for i in range(...):
        for j in range(...):
            # the variables b, i and j index C in the order of their appearance in the equation
            C[b, i, j] = ...

因此,从本质for上讲,每个C的输出索引都有一个循环。我们现在暂时不确定范围。

接下来,我们看一下左侧-是否有没有出现在右侧的范围变量?在我们的情况下-是,h并且wfor为每个此类变量添加一个内部嵌套循环:

for b in range(...):
    for i in range(...):
        for j in range(...):
            C[b, i, j] = 0
            for h in range(...):
                for w in range(...):
                    ...

现在,在最内层的循环中,我们定义了所有索引,因此我们可以编写实际的求和并完成转换:

# three nested for-loops that index the elements of C
for b in range(...):
    for i in range(...):
        for j in range(...):

            # prepare to sum
            C[b, i, j] = 0

            # two nested for-loops for the two indexes that don't appear on the right-hand side
            for h in range(...):
                for w in range(...):
                    # Sum! Compare the statement below with the original einsum formula
                    # 'bhwi,bhwj->bij'

                    C[b, i, j] += A[b, h, w, i] * B[b, h, w, j]

如果到目前为止您已经能够遵循该代码,那么恭喜您!这就是您需要阅读einsum方程式所需的全部。请特别注意原始einsum公式如何映射到以上代码段中的最终sumsum语句。for循环和范围边界只是模糊不清的,最终声明是您真正需要了解的所有内容。

为了完整起见,让我们看看如何确定每个范围变量的范围。嗯,每个变量的范围只是它索引的维度的长度。显然,如果变量在一个或多个张量中索引一个以上的维度,则每个维度的长度必须相等。这是上面带有完整范围的代码:

# C's shape is determined by the shapes of the inputs
# b indexes both A and B, so its range can come from either A.shape or B.shape
# i indexes only A, so its range can only come from A.shape, the same is true for j and B
assert A.shape[0] == B.shape[0]
assert A.shape[1] == B.shape[1]
assert A.shape[2] == B.shape[2]
C = np.zeros((A.shape[0], A.shape[3], B.shape[3]))
for b in range(A.shape[0]): # b indexes both A and B, or B.shape[0], which must be the same
    for i in range(A.shape[3]):
        for j in range(B.shape[3]):
            # h and w can come from either A or B
            for h in range(A.shape[1]):
                for w in range(A.shape[2]):
                    C[b, i, j] += A[b, h, w, i] * B[b, h, w, j]

When reading einsum equations, I’ve found it the most helpful to just be able to mentally boil them down to their imperative versions.

Let’s start with the following (imposing) statement:

C = np.einsum('bhwi,bhwj->bij', A, B)

Working through the punctuation first we see that we have two 4-letter comma-separated blobs – bhwi and bhwj, before the arrow, and a single 3-letter blob bij after it. Therefore, the equation produces a rank-3 tensor result from two rank-4 tensor inputs.

Now, let each letter in each blob be the name of a range variable. The position at which the letter appears in the blob is the index of the axis that it ranges over in that tensor. The imperative summation that produces each element of C, therefore, has to start with three nested for loops, one for each index of C.

for b in range(...):
    for i in range(...):
        for j in range(...):
            # the variables b, i and j index C in the order of their appearance in the equation
            C[b, i, j] = ...

So, essentially, you have a for loop for every output index of C. We’ll leave the ranges undetermined for now.

Next we look at the left-hand side – are there any range variables there that don’t appear on the right-hand side? In our case – yes, h and w. Add an inner nested for loop for every such variable:

for b in range(...):
    for i in range(...):
        for j in range(...):
            C[b, i, j] = 0
            for h in range(...):
                for w in range(...):
                    ...

Inside the innermost loop we now have all indices defined, so we can write the actual summation and the translation is complete:

# three nested for-loops that index the elements of C
for b in range(...):
    for i in range(...):
        for j in range(...):

            # prepare to sum
            C[b, i, j] = 0

            # two nested for-loops for the two indexes that don't appear on the right-hand side
            for h in range(...):
                for w in range(...):
                    # Sum! Compare the statement below with the original einsum formula
                    # 'bhwi,bhwj->bij'

                    C[b, i, j] += A[b, h, w, i] * B[b, h, w, j]

If you’ve been able to follow the code thus far, then congratulations! This is all you need to be able to read einsum equations. Notice in particular how the original einsum formula maps to the final summation statement in the snippet above. The for-loops and range bounds are just fluff and that final statement is all you really need to understand what’s going on.

For the sake of completeness, let’s see how to determine the ranges for each range variable. Well, the range of each variable is simply the length of the dimension(s) which it indexes. Obviously, if a variable indexes more than one dimension in one or more tensors, then the lengths of each of those dimensions have to be equal. Here’s the code above with the complete ranges:

# C's shape is determined by the shapes of the inputs
# b indexes both A and B, so its range can come from either A.shape or B.shape
# i indexes only A, so its range can only come from A.shape, the same is true for j and B
assert A.shape[0] == B.shape[0]
assert A.shape[1] == B.shape[1]
assert A.shape[2] == B.shape[2]
C = np.zeros((A.shape[0], A.shape[3], B.shape[3]))
for b in range(A.shape[0]): # b indexes both A and B, or B.shape[0], which must be the same
    for i in range(A.shape[3]):
        for j in range(B.shape[3]):
            # h and w can come from either A or B
            for h in range(A.shape[1]):
                for w in range(A.shape[2]):
                    C[b, i, j] += A[b, h, w, i] * B[b, h, w, j]

numpy.newaxis如何工作以及何时使用?

问题:numpy.newaxis如何工作以及何时使用?

当我尝试

numpy.newaxis

结果为我提供了一个x轴从0到1 numpy.newaxis的二维绘图框。但是,当我尝试使用对向量进行切片时,

vector[0:4,]
[ 0.04965172  0.04979645  0.04994022  0.05008303]
vector[:, np.newaxis][0:4,]
[[ 0.04965172]
[ 0.04979645]
[ 0.04994022]
[ 0.05008303]]

除了将行向量更改为列向量之外,是否一样?

通常,的用途是什么numpy.newaxis,我们应该在什么情况下使用它?

When I try

numpy.newaxis

the result gives me a 2-d plot frame with x-axis from 0 to 1. However, when I try using numpy.newaxis to slice a vector,

vector[0:4,]
[ 0.04965172  0.04979645  0.04994022  0.05008303]
vector[:, np.newaxis][0:4,]
[[ 0.04965172]
[ 0.04979645]
[ 0.04994022]
[ 0.05008303]]

Is it the same thing except that it changes a row vector to a column vector?

Generally, what is the use of numpy.newaxis, and in which circumstances should we use it?


回答 0

简而言之,当使用一次时,用于将现有数组的尺寸numpy.newaxis增加一维。从而,

  • 一维阵列将变为二维阵列

  • 2D阵列将变为3D阵列

  • 3D阵列将变成4D阵列

  • 4D阵列将变为5D阵列

等等..

这里是一个视觉说明描绘促进 1D阵列以二维阵列。


方案1:如上图所示,np.newaxis当您想将一维数组显式转换为行向量列向量时,可能会派上用场。

例:

# 1D array
In [7]: arr = np.arange(4)
In [8]: arr.shape
Out[8]: (4,)

# make it as row vector by inserting an axis along first dimension
In [9]: row_vec = arr[np.newaxis, :]     # arr[None, :]
In [10]: row_vec.shape
Out[10]: (1, 4)

# make it as column vector by inserting an axis along second dimension
In [11]: col_vec = arr[:, np.newaxis]     # arr[:, None]
In [12]: col_vec.shape
Out[12]: (4, 1)

场景2:当我们想将numpy广播用作某些操作的一部分时,例如在添加一些数组时。

例:

假设您要添加以下两个数组:

 x1 = np.array([1, 2, 3, 4, 5])
 x2 = np.array([5, 4, 3])

如果您尝试像这样添加它们,NumPy将引发以下内容ValueError

ValueError: operands could not be broadcast together with shapes (5,) (3,)

在这种情况下,您可以np.newaxis用来增加数组之一的尺寸,以便NumPy可以广播

In [2]: x1_new = x1[:, np.newaxis]    # x1[:, None]
# now, the shape of x1_new is (5, 1)
# array([[1],
#        [2],
#        [3],
#        [4],
#        [5]])

现在,添加:

In [3]: x1_new + x2
Out[3]:
array([[ 6,  5,  4],
       [ 7,  6,  5],
       [ 8,  7,  6],
       [ 9,  8,  7],
       [10,  9,  8]])

另外,您也可以向数组添加新轴x2

In [6]: x2_new = x2[:, np.newaxis]    # x2[:, None]
In [7]: x2_new     # shape is (3, 1)
Out[7]: 
array([[5],
       [4],
       [3]])

现在,添加:

In [8]: x1 + x2_new
Out[8]: 
array([[ 6,  7,  8,  9, 10],
       [ 5,  6,  7,  8,  9],
       [ 4,  5,  6,  7,  8]])

注意请注意,在两种情况下我们都得到相同的结果(但一种是另一种的转置)。


方案3:这类似于方案1。但是,你可以使用np.newaxis不止一次地促进阵列更高的层面。有时对于高阶数组(即Tensors)需要这样的操作。

例:

In [124]: arr = np.arange(5*5).reshape(5,5)

In [125]: arr.shape
Out[125]: (5, 5)

# promoting 2D array to a 5D array
In [126]: arr_5D = arr[np.newaxis, ..., np.newaxis, np.newaxis]    # arr[None, ..., None, None]

In [127]: arr_5D.shape
Out[127]: (1, 5, 5, 1, 1)

关于np.newaxisnp.reshape的更多背景

newaxis 也称为伪索引,它允许将轴临时添加到多数组中。

np.newaxis使用切片运算符来重新创建阵列而np.reshape重塑阵列所需的布局(假设尺寸匹配;这是必须reshape发生)。

In [13]: A = np.ones((3,4,5,6))
In [14]: B = np.ones((4,6))
In [15]: (A + B[:, np.newaxis, :]).shape     # B[:, None, :]
Out[15]: (3, 4, 5, 6)

在上面的示例中,我们在B(使用广播)的第一和第二轴之间插入了一个临时轴。此处使用缺失轴来填充,np.newaxis以使广播操作正常进行。


一般提示:您也可以None代替使用np.newaxis;这些实际上是相同的对象

In [13]: np.newaxis is None
Out[13]: True

PS也看到了一个很好的答案:newaxis vs reshape添加尺寸

Simply put, numpy.newaxis is used to increase the dimension of the existing array by one more dimension, when used once. Thus,

  • 1D array will become 2D array

  • 2D array will become 3D array

  • 3D array will become 4D array

  • 4D array will become 5D array

and so on..

Here is a visual illustration which depicts promotion of 1D array to 2D arrays.


Scenario-1: np.newaxis might come in handy when you want to explicitly convert a 1D array to either a row vector or a column vector, as depicted in the above picture.

Example:

# 1D array
In [7]: arr = np.arange(4)
In [8]: arr.shape
Out[8]: (4,)

# make it as row vector by inserting an axis along first dimension
In [9]: row_vec = arr[np.newaxis, :]     # arr[None, :]
In [10]: row_vec.shape
Out[10]: (1, 4)

# make it as column vector by inserting an axis along second dimension
In [11]: col_vec = arr[:, np.newaxis]     # arr[:, None]
In [12]: col_vec.shape
Out[12]: (4, 1)

Scenario-2: When we want to make use of numpy broadcasting as part of some operation, for instance while doing addition of some arrays.

Example:

Let’s say you want to add the following two arrays:

 x1 = np.array([1, 2, 3, 4, 5])
 x2 = np.array([5, 4, 3])

If you try to add these just like that, NumPy will raise the following ValueError :

ValueError: operands could not be broadcast together with shapes (5,) (3,)

In this situation, you can use np.newaxis to increase the dimension of one of the arrays so that NumPy can broadcast.

In [2]: x1_new = x1[:, np.newaxis]    # x1[:, None]
# now, the shape of x1_new is (5, 1)
# array([[1],
#        [2],
#        [3],
#        [4],
#        [5]])

Now, add:

In [3]: x1_new + x2
Out[3]:
array([[ 6,  5,  4],
       [ 7,  6,  5],
       [ 8,  7,  6],
       [ 9,  8,  7],
       [10,  9,  8]])

Alternatively, you can also add new axis to the array x2:

In [6]: x2_new = x2[:, np.newaxis]    # x2[:, None]
In [7]: x2_new     # shape is (3, 1)
Out[7]: 
array([[5],
       [4],
       [3]])

Now, add:

In [8]: x1 + x2_new
Out[8]: 
array([[ 6,  7,  8,  9, 10],
       [ 5,  6,  7,  8,  9],
       [ 4,  5,  6,  7,  8]])

Note: Observe that we get the same result in both cases (but one being the transpose of the other).


Scenario-3: This is similar to scenario-1. But, you can use np.newaxis more than once to promote the array to higher dimensions. Such an operation is sometimes needed for higher order arrays (i.e. Tensors).

Example:

In [124]: arr = np.arange(5*5).reshape(5,5)

In [125]: arr.shape
Out[125]: (5, 5)

# promoting 2D array to a 5D array
In [126]: arr_5D = arr[np.newaxis, ..., np.newaxis, np.newaxis]    # arr[None, ..., None, None]

In [127]: arr_5D.shape
Out[127]: (1, 5, 5, 1, 1)

As an alternative, you can use numpy.expand_dims that has an intuitive axis kwarg.

# adding new axes at 1st, 4th, and last dimension of the resulting array
In [131]: newaxes = (0, 3, -1)
In [132]: arr_5D = np.expand_dims(arr, axis=newaxes)
In [133]: arr_5D.shape
Out[133]: (1, 5, 5, 1, 1)

More background on np.newaxis vs np.reshape

newaxis is also called as a pseudo-index that allows the temporary addition of an axis into a multiarray.

np.newaxis uses the slicing operator to recreate the array while numpy.reshape reshapes the array to the desired layout (assuming that the dimensions match; And this is must for a reshape to happen).

Example

In [13]: A = np.ones((3,4,5,6))
In [14]: B = np.ones((4,6))
In [15]: (A + B[:, np.newaxis, :]).shape     # B[:, None, :]
Out[15]: (3, 4, 5, 6)

In the above example, we inserted a temporary axis between the first and second axes of B (to use broadcasting). A missing axis is filled-in here using np.newaxis to make the broadcasting operation work.


General Tip: You can also use None in place of np.newaxis; These are in fact the same objects.

In [13]: np.newaxis is None
Out[13]: True

P.S. Also see this great answer: newaxis vs reshape to add dimensions


回答 1

什么np.newaxis

np.newaxis仅仅是Python的常量的别名None,这意味着无论你使用np.newaxis,你也可以使用None

>>> np.newaxis is None
True

如果您阅读使用而不是的代码,则更具描述np.newaxisNone

如何使用np.newaxis

np.newaxis,通常使用与切片。它表示您要向数组添加其他维度。的位置np.newaxis代表我要添加尺寸的位置。

>>> import numpy as np
>>> a = np.arange(10)
>>> a
array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
>>> a.shape
(10,)

在第一个示例中,我使用第一个维度中的所有元素并添加第二个维度:

>>> a[:, np.newaxis]
array([[0],
       [1],
       [2],
       [3],
       [4],
       [5],
       [6],
       [7],
       [8],
       [9]])
>>> a[:, np.newaxis].shape
(10, 1)

第二个示例将一个维添加为第一维,然后将原始数组的第一维中的所有元素用作结果数组的第二维中的元素:

>>> a[np.newaxis, :]  # The output has 2 [] pairs!
array([[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]])
>>> a[np.newaxis, :].shape
(1, 10)

同样,您可以使用多个np.newaxis添加多个尺寸:

>>> a[np.newaxis, :, np.newaxis]  # note the 3 [] pairs in the output
array([[[0],
        [1],
        [2],
        [3],
        [4],
        [5],
        [6],
        [7],
        [8],
        [9]]])
>>> a[np.newaxis, :, np.newaxis].shape
(1, 10, 1)

有替代品np.newaxis吗?

NumPy:还有另一种非常相似的功能,np.expand_dims也可以用于插入一个尺寸:

>>> np.expand_dims(a, 1)  # like a[:, np.newaxis]
>>> np.expand_dims(a, 0)  # like a[np.newaxis, :]

但是考虑到它只是在中插入1s,shape您也可以reshape在数组中添加以下尺寸:

>>> a.reshape(a.shape + (1,))  # like a[:, np.newaxis]
>>> a.reshape((1,) + a.shape)  # like a[np.newaxis, :]

大多数情况下np.newaxis,添加尺寸是最简单的方法,但是最好知道替代方法。

什么时候使用np.newaxis

在某些情况下,添加尺寸很有用:

  • 数据是否应具有指定的维数。例如,如果要matplotlib.pyplot.imshow用于显示一维数组。

  • 如果您想让NumPy广播数组。通过添加维度,您可以例如获取一个数组的所有元素之间的差:a - a[:, np.newaxis]。之所以可行,是因为NumPy操作从最后一个维度1开始广播。

  • 添加必要的尺寸,以便NumPy 可以广播数组。这是可行的,因为每个length-1维仅被广播到另一个数组的对应1维的长度。


1如果您想了解有关广播规则的更多信息,关于该主题NumPy文档非常好。它还包括一个示例np.newaxis

>>> a = np.array([0.0, 10.0, 20.0, 30.0])
>>> b = np.array([1.0, 2.0, 3.0])
>>> a[:, np.newaxis] + b
array([[  1.,   2.,   3.],
       [ 11.,  12.,  13.],
       [ 21.,  22.,  23.],
       [ 31.,  32.,  33.]])

What is np.newaxis?

The np.newaxis is just an alias for the Python constant None, which means that wherever you use np.newaxis you could also use None:

>>> np.newaxis is None
True

It’s just more descriptive if you read code that uses np.newaxis instead of None.

How to use np.newaxis?

The np.newaxis is generally used with slicing. It indicates that you want to add an additional dimension to the array. The position of the np.newaxis represents where I want to add dimensions.

>>> import numpy as np
>>> a = np.arange(10)
>>> a
array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
>>> a.shape
(10,)

In the first example I use all elements from the first dimension and add a second dimension:

>>> a[:, np.newaxis]
array([[0],
       [1],
       [2],
       [3],
       [4],
       [5],
       [6],
       [7],
       [8],
       [9]])
>>> a[:, np.newaxis].shape
(10, 1)

The second example adds a dimension as first dimension and then uses all elements from the first dimension of the original array as elements in the second dimension of the result array:

>>> a[np.newaxis, :]  # The output has 2 [] pairs!
array([[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]])
>>> a[np.newaxis, :].shape
(1, 10)

Similarly you can use multiple np.newaxis to add multiple dimensions:

>>> a[np.newaxis, :, np.newaxis]  # note the 3 [] pairs in the output
array([[[0],
        [1],
        [2],
        [3],
        [4],
        [5],
        [6],
        [7],
        [8],
        [9]]])
>>> a[np.newaxis, :, np.newaxis].shape
(1, 10, 1)

Are there alternatives to np.newaxis?

There is another very similar functionality in NumPy: np.expand_dims, which can also be used to insert one dimension:

>>> np.expand_dims(a, 1)  # like a[:, np.newaxis]
>>> np.expand_dims(a, 0)  # like a[np.newaxis, :]

But given that it just inserts 1s in the shape you could also reshape the array to add these dimensions:

>>> a.reshape(a.shape + (1,))  # like a[:, np.newaxis]
>>> a.reshape((1,) + a.shape)  # like a[np.newaxis, :]

Most of the times np.newaxis is the easiest way to add dimensions, but it’s good to know the alternatives.

When to use np.newaxis?

In several contexts is adding dimensions useful:

  • If the data should have a specified number of dimensions. For example if you want to use matplotlib.pyplot.imshow to display a 1D array.

  • If you want NumPy to broadcast arrays. By adding a dimension you could for example get the difference between all elements of one array: a - a[:, np.newaxis]. This works because NumPy operations broadcast starting with the last dimension 1.

  • To add a necessary dimension so that NumPy can broadcast arrays. This works because each length-1 dimension is simply broadcast to the length of the corresponding1 dimension of the other array.


1 If you want to read more about the broadcasting rules the NumPy documentation on that subject is very good. It also includes an example with np.newaxis:

>>> a = np.array([0.0, 10.0, 20.0, 30.0])
>>> b = np.array([1.0, 2.0, 3.0])
>>> a[:, np.newaxis] + b
array([[  1.,   2.,   3.],
       [ 11.,  12.,  13.],
       [ 21.,  22.,  23.],
       [ 31.,  32.,  33.]])

回答 2

您从一维数字列表开始。使用完后numpy.newaxis,您将其转换为二维矩阵,每个矩阵由四行组成。

然后,您可以使用该矩阵进行矩阵乘法,或者将其用于构建更大的4 xn矩阵。

You started with a one-dimensional list of numbers. Once you used numpy.newaxis, you turned it into a two-dimensional matrix, consisting of four rows of one column each.

You could then use that matrix for matrix multiplication, or involve it in the construction of a larger 4 x n matrix.


回答 3

newaxis选择元组中的object对象用于将结果选择的尺寸扩展一个单位长度尺寸。

这不仅仅是行矩阵到列矩阵的转换。

考虑下面的示例:

In [1]:x1 = np.arange(1,10).reshape(3,3)
       print(x1)
Out[1]: array([[1, 2, 3],
               [4, 5, 6],
               [7, 8, 9]])

现在让我们为数据添加新维度,

In [2]:x1_new = x1[:,np.newaxis]
       print(x1_new)
Out[2]:array([[[1, 2, 3]],

              [[4, 5, 6]],

              [[7, 8, 9]]])

您可以newaxis在此处看到添加了额外的维度,x1的维度为(3,3),X1_new的维度为(3,1,3)。

我们的新维度如何使我们能够进行不同的操作:

In [3]:x2 = np.arange(11,20).reshape(3,3)
       print(x2)
Out[3]:array([[11, 12, 13],
              [14, 15, 16],
              [17, 18, 19]]) 

将x1_new和x2相加,我们得到:

In [4]:x1_new+x2
Out[4]:array([[[12, 14, 16],
               [15, 17, 19],
               [18, 20, 22]],

              [[15, 17, 19],
               [18, 20, 22],
               [21, 23, 25]],

              [[18, 20, 22],
               [21, 23, 25],
               [24, 26, 28]]])

因此,newaxis不仅仅是行到列矩阵的转换。它增加了矩阵的维数,从而使我们能够对其进行更多操作。

newaxis object in the selection tuple serves to expand the dimensions of the resulting selection by one unit-length dimension.

It is not just conversion of row matrix to column matrix.

Consider the example below:

In [1]:x1 = np.arange(1,10).reshape(3,3)
       print(x1)
Out[1]: array([[1, 2, 3],
               [4, 5, 6],
               [7, 8, 9]])

Now lets add new dimension to our data,

In [2]:x1_new = x1[:,np.newaxis]
       print(x1_new)
Out[2]:array([[[1, 2, 3]],

              [[4, 5, 6]],

              [[7, 8, 9]]])

You can see that newaxis added the extra dimension here, x1 had dimension (3,3) and X1_new has dimension (3,1,3).

How our new dimension enables us to different operations:

In [3]:x2 = np.arange(11,20).reshape(3,3)
       print(x2)
Out[3]:array([[11, 12, 13],
              [14, 15, 16],
              [17, 18, 19]]) 

Adding x1_new and x2, we get:

In [4]:x1_new+x2
Out[4]:array([[[12, 14, 16],
               [15, 17, 19],
               [18, 20, 22]],

              [[15, 17, 19],
               [18, 20, 22],
               [21, 23, 25]],

              [[18, 20, 22],
               [21, 23, 25],
               [24, 26, 28]]])

Thus, newaxis is not just conversion of row to column matrix. It increases the dimension of matrix, thus enabling us to do more operations on it.


numpy中的ndarray和array有什么区别?

问题:numpy中的ndarray和array有什么区别?

ndarrayarrayNumpy有什么区别?我在哪里可以找到numpy源代码中的实现?

What is the difference between ndarray and array in Numpy? And where can I find the implementations in the numpy source code?


回答 0

numpy.array只是创建一个便利函数ndarray; 它本身不是类。

您也可以使用创建数组numpy.ndarray,但不建议这样做。来自的文档字符串numpy.ndarray

阵列应该使用来构造arrayzerosempty…这里给出的参数是指低级方法(ndarray(...)用于实例化阵列)。

实现的大部分内容都在C代码中(在multiarray中),但是您可以在这里开始查看ndarray接口:

https://github.com/numpy/numpy/blob/master/numpy/core/numeric.py

numpy.array is just a convenience function to create an ndarray; it is not a class itself.

You can also create an array using numpy.ndarray, but it is not the recommended way. From the docstring of numpy.ndarray:

Arrays should be constructed using array, zeros or empty … The parameters given here refer to a low-level method (ndarray(...)) for instantiating an array.

Most of the meat of the implementation is in C code, here in multiarray, but you can start looking at the ndarray interfaces here:

https://github.com/numpy/numpy/blob/master/numpy/core/numeric.py


回答 1

numpy.array是一个返回的函数numpy.ndarray。没有对象类型numpy.array。

numpy.array is a function that returns a numpy.ndarray. There is no object type numpy.array.


回答 2

只需几行示例代码即可显示numpy.array和numpy.ndarray之间的区别

热身步骤:构建列表

a = [1,2,3]

检查类型

print(type(a))

你会得到

<class 'list'>

使用np.array构造一个数组(从列表中)

a = np.array(a)

或者,您可以跳过热身步骤,直接进行

a = np.array([1,2,3])

检查类型

print(type(a))

你会得到

<class 'numpy.ndarray'>

告诉你numpy数组的类型是numpy.ndarray

您还可以通过以下方式检查类型

isinstance(a, (np.ndarray))

你会得到

True

以下两行均会给您一条错误消息

np.ndarray(a)                # should be np.array(a)
isinstance(a, (np.array))    # should be isinstance(a, (np.ndarray))

Just a few lines of example code to show the difference between numpy.array and numpy.ndarray

Warm up step: Construct a list

a = [1,2,3]

Check the type

print(type(a))

You will get

<class 'list'>

Construct an array (from a list) using np.array

a = np.array(a)

Or, you can skip the warm up step, directly have

a = np.array([1,2,3])

Check the type

print(type(a))

You will get

<class 'numpy.ndarray'>

which tells you the type of the numpy array is numpy.ndarray

You can also check the type by

isinstance(a, (np.ndarray))

and you will get

True

Either of the following two lines will give you an error message

np.ndarray(a)                # should be np.array(a)
isinstance(a, (np.array))    # should be isinstance(a, (np.ndarray))

回答 3

numpy.ndarray()是一个类,numpy.array()而是要创建的方法/函数ndarray

在numpy docs中,如果您想从ndarray类创建数组,则可以使用以下两种方式进行引用:

1-使用array()zeros()empty()方法: 阵列应该使用数组,零或空构造(参考也参见下文部分)。此处给出的参数指的是ndarray(…)用于实例化数组的低级方法()。

2- ndarray直接来自类: 有两种创建数组的方式__new__:使用:如果buffer为None,则仅使用shape,dtype和order。如果buffer是暴露buffer接口的对象,则将解释所有关键字。

下面的示例给出了一个随机数组,因为我们没有分配缓冲区值:

np.ndarray(shape=(2,2), dtype=float, order='F', buffer=None)

array([[ -1.13698227e+002,   4.25087011e-303],
       [  2.88528414e-306,   3.27025015e-309]])         #random

另一个示例是将数组对象分配给缓冲区示例:

>>> np.ndarray((2,), buffer=np.array([1,2,3]),
...            offset=np.int_().itemsize,
...            dtype=int) # offset = 1*itemsize, i.e. skip first element
array([2, 3])

从上面的示例中,我们注意到我们无法为“缓冲区”分配列表,我们不得不使用numpy.array()返回缓冲区的ndarray对象

结论:numpy.array()如果要制造numpy.ndarray()物体,则使用“

numpy.ndarray() is a class, while numpy.array() is a method / function to create ndarray.

In numpy docs if you want to create an array from ndarray class you can do it with 2 ways as quoted:

1- using array(), zeros() or empty() methods: Arrays should be constructed using array, zeros or empty (refer to the See Also section below). The parameters given here refer to a low-level method (ndarray(…)) for instantiating an array.

2- from ndarray class directly: There are two modes of creating an array using __new__: If buffer is None, then only shape, dtype, and order are used. If buffer is an object exposing the buffer interface, then all keywords are interpreted.

The example below gives a random array because we didn’t assign buffer value:

np.ndarray(shape=(2,2), dtype=float, order='F', buffer=None)

array([[ -1.13698227e+002,   4.25087011e-303],
       [  2.88528414e-306,   3.27025015e-309]])         #random

another example is to assign array object to the buffer example:

>>> np.ndarray((2,), buffer=np.array([1,2,3]),
...            offset=np.int_().itemsize,
...            dtype=int) # offset = 1*itemsize, i.e. skip first element
array([2, 3])

from above example we notice that we can’t assign a list to “buffer” and we had to use numpy.array() to return ndarray object for the buffer

Conclusion: use numpy.array() if you want to make a numpy.ndarray() object”


回答 4

我认为与np.array()您一起只能创建C,尽管您提到了该命令,但是当您使用np.isfortran()它检查时说是false。但是,np.ndarrray()当您指定订单时,它将根据提供的订单创建订单。

I think with np.array() you can only create C like though you mention the order, when you check using np.isfortran() it says false. but with np.ndarrray() when you specify the order it creates based on the order provided.


如何从多维数组中提取列?

问题:如何从多维数组中提取列?

有人知道如何在Python中从多维数组中提取列吗?

Does anybody know how to extract a column from a multi-dimensional array in Python?


回答 0

>>> import numpy as np
>>> A = np.array([[1,2,3,4],[5,6,7,8]])

>>> A
array([[1, 2, 3, 4],
    [5, 6, 7, 8]])

>>> A[:,2] # returns the third columm
array([3, 7])

另请参阅:“ numpy.arange”和“ reshape”以分配内存

示例:(使用矩阵整形(3×4)分配数组)

nrows = 3
ncols = 4
my_array = numpy.arange(nrows*ncols, dtype='double')
my_array = my_array.reshape(nrows, ncols)
>>> import numpy as np
>>> A = np.array([[1,2,3,4],[5,6,7,8]])

>>> A
array([[1, 2, 3, 4],
    [5, 6, 7, 8]])

>>> A[:,2] # returns the third columm
array([3, 7])

See also: “numpy.arange” and “reshape” to allocate memory

Example: (Allocating a array with shaping of matrix (3×4))

nrows = 3
ncols = 4
my_array = numpy.arange(nrows*ncols, dtype='double')
my_array = my_array.reshape(nrows, ncols)

回答 1

可能是您正在使用NumPy数组吗?Python具有数组模块,但是不支持多维数组。普通的Python列表也是一维的。

但是,如果您有一个简单的二维列表,例如:

A = [[1,2,3,4],
     [5,6,7,8]]

然后您可以提取一个像这样的列:

def column(matrix, i):
    return [row[i] for row in matrix]

提取第二列(索引1):

>>> column(A, 1)
[2, 6]

或者,简单地:

>>> [row[1] for row in A]
[2, 6]

Could it be that you’re using a NumPy array? Python has the array module, but that does not support multi-dimensional arrays. Normal Python lists are single-dimensional too.

However, if you have a simple two-dimensional list like this:

A = [[1,2,3,4],
     [5,6,7,8]]

then you can extract a column like this:

def column(matrix, i):
    return [row[i] for row in matrix]

Extracting the second column (index 1):

>>> column(A, 1)
[2, 6]

Or alternatively, simply:

>>> [row[1] for row in A]
[2, 6]

回答 2

如果你有一个像

a = [[1, 2], [2, 3], [3, 4]]

然后像这样提取第一列:

[row[0] for row in a]

所以结果看起来像这样:

[1, 2, 3]

If you have an array like

a = [[1, 2], [2, 3], [3, 4]]

Then you extract the first column like that:

[row[0] for row in a]

So the result looks like this:

[1, 2, 3]

回答 3

看看这个!

a = [[1, 2], [2, 3], [3, 4]]
a2 = zip(*a)
a2[0]

它与上面相同,只是它使zip工作更整洁,但需要单个数组作为参数,* a语法将多维数组解压缩为单个数组参数

check it out!

a = [[1, 2], [2, 3], [3, 4]]
a2 = zip(*a)
a2[0]

it is the same thing as above except somehow it is neater the zip does the work but requires single arrays as arguments, the *a syntax unpacks the multidimensional array into single array arguments


回答 4

def get_col(arr, col):
    return map(lambda x : x[col], arr)

a = [[1,2,3,4], [5,6,7,8], [9,10,11,12],[13,14,15,16]]

print get_col(a, 3)

Python中的map函数是另一种方法。

def get_col(arr, col):
    return map(lambda x : x[col], arr)

a = [[1,2,3,4], [5,6,7,8], [9,10,11,12],[13,14,15,16]]

print get_col(a, 3)

map function in Python is another way to go.


回答 5

>>> x = arange(20).reshape(4,5)
>>> x array([[ 0,  1,  2,  3,  4],
        [ 5,  6,  7,  8,  9],
        [10, 11, 12, 13, 14],
        [15, 16, 17, 18, 19]])

如果您想使用第二栏,可以使用

>>> x[:, 1]
array([ 1,  6, 11, 16])
>>> x = arange(20).reshape(4,5)
>>> x array([[ 0,  1,  2,  3,  4],
        [ 5,  6,  7,  8,  9],
        [10, 11, 12, 13, 14],
        [15, 16, 17, 18, 19]])

if you want the second column you can use

>>> x[:, 1]
array([ 1,  6, 11, 16])

回答 6

[matrix[i][column] for i in range(len(matrix))]
[matrix[i][column] for i in range(len(matrix))]

回答 7

如果您喜欢map-reduce样式的python,而不是列表推导,itemgetter运算符也可以提供帮助!

# tested in 2.4
from operator import itemgetter
def column(matrix,i):
    f = itemgetter(i)
    return map(f,matrix)

M = [range(x,x+5) for x in range(10)]
assert column(M,1) == range(1,11)

The itemgetter operator can help too, if you like map-reduce style python, rather than list comprehensions, for a little variety!

# tested in 2.4
from operator import itemgetter
def column(matrix,i):
    f = itemgetter(i)
    return map(f,matrix)

M = [range(x,x+5) for x in range(10)]
assert column(M,1) == range(1,11)

回答 8

您也可以使用此:

values = np.array([[1,2,3],[4,5,6]])
values[...,0] # first column
#[1,4]

注意:这不适用于内置数组且未对齐(例如np.array([[1,2,3],[4,5,6,7]]))

You can use this as well:

values = np.array([[1,2,3],[4,5,6]])
values[...,0] # first column
#[1,4]

Note: This is not working for built-in array and not aligned (e.g. np.array([[1,2,3],[4,5,6,7]]) )


回答 9

我想您想从数组(例如下面的数组)中提取列

import numpy as np
A = np.array([[1,2,3,4],[5,6,7,8],[9,10,11,12]])

现在,如果要获取格式的第三列

D=array[[3],
[7],
[11]]

然后,您需要首先使数组成为矩阵

B=np.asmatrix(A)
C=B[:,2]
D=asarray(C)

现在,您可以像在excel中一样进行元素明智的计算。

I think you want to extract a column from an array such as an array below

import numpy as np
A = np.array([[1,2,3,4],[5,6,7,8],[9,10,11,12]])

Now if you want to get the third column in the format

D=array[[3],
[7],
[11]]

Then you need to first make the array a matrix

B=np.asmatrix(A)
C=B[:,2]
D=asarray(C)

And now you can do element wise calculations much like you would do in excel.


回答 10

假设我们有n X m矩阵(n行和m列)说5行和4列

matrix = [[1,2,3,4],[5,6,7,8],[9,10,11,12],[13,14,15,16],[17,18,19,20]]

要提取python中的列,我们可以像这样使用列表理解

[ [row[i] for row in matrix] for in range(4) ]

您可以将矩阵中的列数替换为4。结果是

[ [1,5,9,13,17],[2,10,14,18],[3,7,11,15,19],[4,8,12,16,20] ]

let’s say we have n X m matrix(n rows and m columns) say 5 rows and 4 columns

matrix = [[1,2,3,4],[5,6,7,8],[9,10,11,12],[13,14,15,16],[17,18,19,20]]

To extract the columns in python, we can use list comprehension like this

[ [row[i] for row in matrix] for in range(4) ]

You can replace 4 by whatever number of columns your matrix has. The result is

[ [1,5,9,13,17],[2,10,14,18],[3,7,11,15,19],[4,8,12,16,20] ]


回答 11

array = [[1,2,3,4],[5,6,7,8],[9,10,11,12],[13,14,15,16]]

col1 = [val[1] for val in array]
col2 = [val[2] for val in array]
col3 = [val[3] for val in array]
col4 = [val[4] for val in array]
print(col1)
print(col2)
print(col3)
print(col4)

Output:
[1, 5, 9, 13]
[2, 6, 10, 14]
[3, 7, 11, 15]
[4, 8, 12, 16]
array = [[1,2,3,4],[5,6,7,8],[9,10,11,12],[13,14,15,16]]

col1 = [val[1] for val in array]
col2 = [val[2] for val in array]
col3 = [val[3] for val in array]
col4 = [val[4] for val in array]
print(col1)
print(col2)
print(col3)
print(col4)

Output:
[1, 5, 9, 13]
[2, 6, 10, 14]
[3, 7, 11, 15]
[4, 8, 12, 16]

回答 12

使用矩阵的另一种方法

>>> from numpy import matrix
>>> a = [ [1,2,3],[4,5,6],[7,8,9] ]
>>> matrix(a).transpose()[1].getA()[0]
array([2, 5, 8])
>>> matrix(a).transpose()[0].getA()[0]
array([1, 4, 7])

One more way using matrices

>>> from numpy import matrix
>>> a = [ [1,2,3],[4,5,6],[7,8,9] ]
>>> matrix(a).transpose()[1].getA()[0]
array([2, 5, 8])
>>> matrix(a).transpose()[0].getA()[0]
array([1, 4, 7])

回答 13

如果您在Python中有一个二维数组(不是numpy),则可以像这样提取所有列,

data = [
['a', 1, 2], 
['b', 3, 4], 
['c', 5, 6]
]

columns = list(zip(*data))

print("column[0] = {}".format(columns[0]))
print("column[1] = {}".format(columns[1]))
print("column[2] = {}".format(columns[2]))

执行此代码会产生

>>> print("column[0] = {}".format(columns[0]))
column[0] = ('a', 'b', 'c')

>>> print("column[1] = {}".format(columns[1]))
column[1] = (1, 3, 5)

>>> print("column[2] = {}".format(columns[2]))
column[2] = (2, 4, 6)

当然,您可以按索引提取单个列(例如columns[0]

If you have a two-dimensional array in Python (not numpy), you can extract all the columns like so,

data = [
['a', 1, 2], 
['b', 3, 4], 
['c', 5, 6]
]

columns = list(zip(*data))

print("column[0] = {}".format(columns[0]))
print("column[1] = {}".format(columns[1]))
print("column[2] = {}".format(columns[2]))

Executing this code will yield,

>>> print("column[0] = {}".format(columns[0]))
column[0] = ('a', 'b', 'c')

>>> print("column[1] = {}".format(columns[1]))
column[1] = (1, 3, 5)

>>> print("column[2] = {}".format(columns[2]))
column[2] = (2, 4, 6)

Of course, you can extract a single column by index (e.g. columns[0])


回答 14

尽管使用zip(*iterable)了转置嵌套列表,但是如果嵌套列表的长度不同,也可以使用以下内容:

map(None, *[(1,2,3,), (4,5,), (6,)])

结果是:

[(1, 4, 6), (2, 5, None), (3, None, None)]

因此,第一列是:

map(None, *[(1,2,3,), (4,5,), (6,)])[0]
#>(1, 4, 6)

Despite using zip(*iterable) to transpose a nested list, you can also use the following if the nested lists vary in length:

map(None, *[(1,2,3,), (4,5,), (6,)])

results in:

[(1, 4, 6), (2, 5, None), (3, None, None)]

The first column is thus:

map(None, *[(1,2,3,), (4,5,), (6,)])[0]
#>(1, 4, 6)

回答 15

好吧,有点晚…

如果性能很重要并且您的数据呈矩形,则也可以将其存储为一维,并通过常规切片访问列,例如…

A = [[1,2,3,4],[5,6,7,8]]     #< assume this 4x2-matrix
B = reduce( operator.add, A ) #< get it one-dimensional

def column1d( matrix, dimX, colIdx ):
  return matrix[colIdx::dimX]

def row1d( matrix, dimX, rowIdx ):
  return matrix[rowIdx:rowIdx+dimX] 

>>> column1d( B, 4, 1 )
[2, 6]
>>> row1d( B, 4, 1 )
[2, 3, 4, 5]

整洁的是,这真的很快。但是,负索引在这里不起作用!因此,您无法按索引-1访问最后一列或最后一行。

如果需要负索引,可以稍微调整访问器功能,例如

def column1d( matrix, dimX, colIdx ):
  return matrix[colIdx % dimX::dimX]

def row1d( matrix, dimX, dimY, rowIdx ):
  rowIdx = (rowIdx % dimY) * dimX
  return matrix[rowIdx:rowIdx+dimX]

Well a ‘bit’ late …

In case performance matters and your data is shaped rectangular, you might also store it in one dimension and access the columns by regular slicing e.g. …

A = [[1,2,3,4],[5,6,7,8]]     #< assume this 4x2-matrix
B = reduce( operator.add, A ) #< get it one-dimensional

def column1d( matrix, dimX, colIdx ):
  return matrix[colIdx::dimX]

def row1d( matrix, dimX, rowIdx ):
  return matrix[rowIdx:rowIdx+dimX] 

>>> column1d( B, 4, 1 )
[2, 6]
>>> row1d( B, 4, 1 )
[2, 3, 4, 5]

The neat thing is this is really fast. However, negative indexes don’t work here! So you can’t access the last column or row by index -1.

If you need negative indexing you can tune the accessor-functions a bit, e.g.

def column1d( matrix, dimX, colIdx ):
  return matrix[colIdx % dimX::dimX]

def row1d( matrix, dimX, dimY, rowIdx ):
  rowIdx = (rowIdx % dimY) * dimX
  return matrix[rowIdx:rowIdx+dimX]

回答 16

如果要获取不止一列,请使用slice:

 a = np.array([[1, 2, 3],[4, 5, 6],[7, 8, 9]])
    print(a[:, [1, 2]])
[[2 3]
[5 6]
[8 9]]

If you want to grab more than just one column just use slice:

 a = np.array([[1, 2, 3],[4, 5, 6],[7, 8, 9]])
    print(a[:, [1, 2]])
[[2 3]
[5 6]
[8 9]]

回答 17

我更喜欢下一条提示:将矩阵命名为matrix_ause column_number,例如:

import numpy as np
matrix_a = np.array([[1,2,3,4],[5,6,7,8],[9,10,11,12]])
column_number=2

# you can get the row from transposed matrix - it will be a column:
col=matrix_a.transpose()[column_number]

I prefer the next hint: having the matrix named matrix_a and use column_number, for example:

import numpy as np
matrix_a = np.array([[1,2,3,4],[5,6,7,8],[9,10,11,12]])
column_number=2

# you can get the row from transposed matrix - it will be a column:
col=matrix_a.transpose()[column_number]

回答 18

只需使用transpose(),然后您就可以像获得行一样轻松获得列

matrix=np.array(originalMatrix).transpose()
print matrix[NumberOfColum]

Just use transpose(), then you can get the colummns as easy as you get rows

matrix=np.array(originalMatrix).transpose()
print matrix[NumberOfColum]

回答 19

矩阵中的所有列到新列表中:

N = len(matrix) 
column_list = [ [matrix[row][column] for row in range(N)] for column in range(N) ]

All columns from a matrix into a new list:

N = len(matrix) 
column_list = [ [matrix[row][column] for row in range(N)] for column in range(N) ]