Opencv-python preparation before learning - Numpy-python detailed tutorial 1

Write directory title here

NumPy - Introduction

NumPy is a Python package. It stands for "Numeric Python". It is a library consisting of multidimensional array objects and a collection of routines for manipulating arrays .

Numeric, the predecessor of NumPy, was developed by Jim Hugunin. Another package, Numarray, has also been developed which has some additional functionality. In 2005, Travis Oliphant created the NumPy package by integrating the functionality of Numarray into the Numeric package. This open source project has many contributors.

NumPy operations

Using NumPy, developers can do the following:

  • Arithmetic and logical operations on arrays .
  • Fourier transform and routines for graphics manipulation.
  • Operations related to linear algebra. NumPy has built-in functions for linear algebra and random number generation.

NumPy – an alternative to MatLab

NumPy is commonly used with SciPy (Scientific Python) and Matplotlib (plotting library). This combination is widely used as an alternative to MatLab, a popular platform for technical computing. However, Python is now considered a more modern and complete programming language as an alternative to MatLab.
NumPy is open source which is an added advantage

NumPy - Ndarray object

The most important object defined in NumPy is the N-dimensional array type called ndarray . It describes a collection of elements of the same type (note: a combination of elements of a fixed type; in the form of an array in C). Items in a collection can be accessed using zero -based indexing.

Each element in an ndarray uses the same sized chunk in memory. Each element in an ndarray is an object of data type object (called dtype ).

Any element extracted from an ndarray object (by slicing) is represented by a Python object of type array scalar.
The following figure shows the relationship between ndarray, data type object (dtype) and array scalar type.
insert image description here

Ndarray (note: Ndarray is numpy data array)

Instances of the ndarray class can be constructed by the different array creation routines described later in this tutorial. Basic ndarrays are created using the array functions in NumPy as follows:

# python
# 笔记:创建一个空ndarray对象
numpy.array 

It creates an ndarray from any object that exposes the array interface, or from any method that returns an array.
(notes:

通过拷贝其他数组对象object来创建一个ndarray对象

暴露接口:
就是你写好了一段程序,提供给别人一个访问的接口,别人不管你怎么实现的,调用者只需知道访问的方法及返回值就可以。如:你写的方法
public int sum(int a,int b){
int c = 0;
....
return c;
}
调用者不管你sum怎么实现,只需知道sum()需要两个int参数,返回值是int即可。
那么,暴露数组接口 即可以理解为返回值为数组的接口。

# Python
# 笔记:创建一个ndarray对象,并用object对其进行初始化
numpy.array(object, dtype = None, copy = True, order = None, subok = False, ndmin = 0) 

The above constructor accepts the following parameters:

  1. object Any object that exposes an array interface method returns an array or any (nested) sequence.
  2. dtype The desired data type of the array, optional.
  3. copy is optional, the default is true, whether the object is copied.
  4. order C (by row), F (by column), or A (any, default).
  5. The array returned by subok is coerced to be an array of the base class by default. If true, subclasses are returned.
  6. ndmin specifies the minimum dimensionality of the returned array.
    (note: subok doesn't understand)

Take a look at the example below to understand better.

Example 1

import numpy as np 
a = np.array([1,2,3])   # 采用暴露数组接口的方式创建ndarray
print a
# 输出如下:
[1, 2, 3]

Example 2 multidimensional array

 # 多于一个维度  
import numpy as np 
a = np.array([[1,  2],  [3,  4]])    # 二维数组
print a
# 输出如下:
[[1, 2] 
 [3, 4]]

Example 3 minimum dimension parameter

 # 最小维度  
import numpy as np 
a = np.array([1, 2, 3, 4, 5], ndmin =  2)  # 最小维度为2  
print a
# 输出如下:
[[1, 2, 3, 4, 5]]      
# 笔记:最小维度为2,但是创建时只用了一维数组,因此ndarray会有一个空维度,即:[ [1, 2, 3, 4, 5] [] ],空维度不显示所以成如上显示 

Example 4 specifying the element type

# dtype 参数  
import numpy as np 
a = np.array([1,  2,  3], dtype = complex)  # 设置类型  complex表示复数; 创建时,将元素转换为负数
print a
# 输出如下:
[ 1.+0.j,  2.+0.j,  3.+0.j]

A **ndarray** object consists of a one-dimensional contiguous region in computer memory, with an indexing scheme that maps each element to a location in the memory block. Memory blocks hold elements either row-wise (C-style) or column-wise (FORTRAN or MatLab-style).

NumPy - data types

NumPy supports a wider variety of numeric types than Python. The following table shows the different scalar data types defined in NumPy.

name describe
bool_ Boolean data type (True or False)
int_ The default integer type (similar to long, int32 or int64 in C)
intc Same as C's int type, generally int32 or int 64
intp Integer type for indexing (similar to C's ssize_t, generally still int32 or int64)
you8 bytes (-128 to 127)
int16 Integer (-32768 to 32767)
int32 Integer (-2147483648 to 2147483647)
int64 Integer (-9223372036854775808 to 9223372036854775807)
uint8 unsigned integer (0 to 255)
uint16 unsigned integer (0 to 65535)
uint32 unsigned integer (0 to 4294967295)
uint64 Unsigned integer (0 to 18446744073709551615)
float_ Shorthand for float64 type
float16 Half-precision floating point number, including: 1 sign bit, 5 exponent bits, 10 mantissa bits
float32 Single-precision floating-point numbers, including: 1 sign bit, 8 exponent bits, 23 mantissa bits
float64 Double-precision floating-point number, including: 1 sign bit, 11 exponent bits, 52 mantissa bits
complex_ Shorthand for the complex128 type, that is, a 128-bit complex number
complex64 complex number, representing a double 32-bit floating-point number (real part and imaginary part)
complex128 complex number, representing a double 64-bit floating point number (real part and imaginary part)

NumPy numeric types are instances of dtype (data type) objects , each with unique characteristics. These types can be np.bool_, np.float32, etc.

data type object (dtype)

A data type object ( dtype ) describes the interpretation of a fixed block of memory corresponding to an array (note: refer to the above figure for easier understanding), depending on the following:

  • data type (integer, float, or Python object)
  • data size
  • Endianness (little endian or big endian)
  • In the case of structured types, the names of the fields, the data type of each field, and the portion of the memory block each field occupies.
  • If the data type is a subsequence, its shape and data type.

The byte order depends on the prefix < or > of the data type.

  • Means that the encoding is little-endian (the least significant byte is stored at the smallest address).
  • Means that the encoding is big-endian (the most significant byte is stored at the smallest address).

dtype can be constructed with the following syntax:

numpy.dtype(object, align, copy)

The parameters are:

  • Object: The object to be converted to the data type.

  • Align: If true, adds spacing to the field, making it C-like.

  • Copy: Generate a new copy of the dtype object, if false, the result is a reference to the built-in data type object.

Example 1

# 使用数组标量类型  
import numpy as np 
dt = np.dtype(np.int32)  
print dt
# 输出如下:
int32

Example 2 int8 is equivalent to i1

Notes: int8, int16, int32, int64 can be replaced by equivalent strings 'i1', 'i2', 'i4', and others. 1 in i1 means 1 byte, and 1 byte is 8 bits, so i1 is equivalent to int8

#int8,int16,int32,int64 可替换为等价的字符串 'i1','i2','i4',以及其他。   
import numpy as np 
 
dt = np.dtype('i4')    # int32  即:4字节*8位 
print dt 
#输出如下:
int32

Example 3 end notation

# 使用端记号  
import numpy as np 
dt = np.dtype('>i4')  
print dt
# 输出如下:

>i4

Note: What's the purpose of the end notation? ?

The following example demonstrates the use of structured data types. Here the field names and corresponding scalar data types are declared.

Example 4 Simple structured data type

Notes: The so-called structured data type refers to the structure of various data types. Note: The use of square brackets when defining structured types. For example: [ ('age', np.int8) ], there is another layer of parentheses inside the square brackets. Square brackets represent a list, parentheses represent a tuple

# 首先创建结构化数据类型。  
import numpy as np 
dt = np.dtype([('age',np.int8)])   # 注意:定义结构化类型时,方括号的使用。[('age',np.int8)] 方括号内还有一层小括号
print dt 

# 输出如下:
[('age', 'i1')] 

Example 5 applies the defined dtype to ndarray objects

# 现在将其应用于 ndarray 对象  
import numpy as np 
 
dt = np.dtype([('age',np.int8)]) 
a = np.array([(10,),(20,),(30,)], dtype = dt)   # 没理解 dt结构化类型 如何定义的ndarray的元素?
print a

# 输出如下:
[(10,) (20,) (30,)]

Note: Didn't understand how the dt structured type defines the elements of ndarray?
See the example below, which explains the role of age, 'age' was originally used as a column name. That is, age = [10 20 30].
The permutation structure of [(10,),(20,),(30,)]:

Column 0 column name: 'age' Column 1 column name: null
line 0 10 null
line 1 20 null
line 2 30 null

Example 6 Usage of ndarray column names

# 文件名称可用于访问 age 列的内容  
import numpy as np 
 
dt = np.dtype([('age',np.int8)]) 
a = np.array([(10,),(20,),(30,)], dtype = dt)  
print a['age']

# 输出如下:
[10 20 30]    # 有疑惑看上例

Example 7 Complex structured data types

The following example defines a structured data type named student with a string field name, an integer field age, and a float field marks. This dtype is applied to ndarray objects.

import numpy as np 
student = np.dtype([('name','S20'),  ('age',  'i1'),  ('marks',  'f4')])  
print student

# 输出如下:
[('name', 'S20'), ('age', 'i1'), ('marks', '<f4')])

Example 8 Complex structured data type definition ndarray

import numpy as np 
 
student = np.dtype([('name','S20'),  ('age',  'i1'),  ('marks',  'f4')]) 
a = np.array([('abc',  21,  50),('xyz',  18,  75)], dtype = student)  
print a

#输出如下:
[('abc', 21, 50.0), ('xyz', 18, 75.0)]

Symbol codes for built-in types

Each built-in type has a character code that uniquely defines it:

  • 'b': Boolean value
  • 'i': signed integer
  • 'u': unsigned integer
  • 'f': floating point
  • 'c': complex floating point
  • 'm': time interval
  • 'M': datetime
  • 'O': Python object
  • 'S', 'a': byte string
  • ‘U’:Unicode
  • 'V': raw data (void)

NumPy - array properties

In this chapter, we discuss various array properties of NumPy.

ndarray.shape attribute and ndarray.reshape() method

This array property returns a tuple containing the dimensions of the array , which can also be used to resize the array .

Example 1 a.shape is an attribute of the array a, returns a tuple containing the dimensions of the array

import numpy as np 
a = np.array([[1,2,3],[4,5,6]])  
print a.shape     # 注意:a.shape是数组a的属性,返回一个元组,该元组包含数组维度。

# 输出如下:
(2, 3)

Example 2 Adjust the array matrix through the shape array

# 这会调整数组大小  
import numpy as np 
 
a = np.array([[1,2,3],[4,5,6]]) 
a.shape =  (3,2)  		# 调整数组 矩阵
print a 

# 输出如下:
[[1, 2] 
 [3, 4] 
 [5, 6]]

Example 3 The reshape function adjusts the array matrix, similar to the shape attribute

NumPy also provides the reshape function to resize arrays.

import numpy as np 
a = np.array([[1,2,3],[4,5,6]]) 
b = a.reshape(3,2)   # 也可以写为:a.shape = (3,2)    b = a
print b

# 输出如下:
[[1, 2] 
 [3, 4] 
 [5, 6]]

ndarray.ndim attribute

This array property returns the dimensionality of the array .

Example 1 np.arange() A way to initialize an array

# 等间隔数字的数组  
import numpy as np 

a = np.arange(24)    # 一种初始化数组的方法
print a

#输出如下:
[0 1  2  3  4  5  6  7  8  9  10  11  12  13  14  15  16 17 18 19 20 21 22 23] 

Example 2 print(a.ndim) Dimensions of the array


# 一维数组  
import numpy as np 
a = np.arange(24) 
print(a.ndim) 
# 现在调整其大小
b = a.reshape(2,4,3)  
print(b) 

# 输出如下:
1   				# print(a.ndim) 
[[[ 0,  1,  2] 		# print(b)  三维数组
  [ 3,  4,  5] 
  [ 6,  7,  8] 
  [ 9, 10, 11]] 
  [[12, 13, 14] 
   [15, 16, 17]
   [18, 19, 20] 
   [21, 22, 23]]] 

numpy.itemsize attribute

This array property returns the length in bytes of each element in the array .

Example 1 byte length of x.itemsize element

# 数组的 dtype 为 int8(一个字节)  
import numpy as np 
x = np.array([1,2,3,4,5], dtype = np.int8)  
print x.itemsize

# 输出如下:   8位一个字节,因此x.itemsize = 1
1

Example 2

# 数组的 dtype 现在为 float32(四个字节)  
import numpy as np 
x = np.array([1,2,3,4,5], dtype = np.float32)  
print x.itemsize

# 输出如下:
4

numpy.flags

The ndarray object has the following attributes. This function returns their current values.

serial number properties and description
C_CONTIGUOUS ( C) arrays in a single, C-style contiguous section
F_CONTIGUOUS (F) arrays in a single, Fortran-style contiguous section
OWNDATA (O) Array memory is borrowed from other objects
WRITEABLE (W) The data area can be written. Setting it to flase locks the data, making it read-only
ALIGNED (A) data and any elements will be properly aligned for the hardware
UPDATEIFCOPY (U) This array is a copy of another array. When this array is freed, the source array will be updated with the elements in this array

example

The following example shows the current flags.

import numpy as np 
x = np.array([1,2,3,4,5])  
print x.flags

# 输出如下:
C_CONTIGUOUS : True 
F_CONTIGUOUS : True 
OWNDATA : True 
WRITEABLE : True 
ALIGNED : True 
UPDATEIFCOPY : False

NumPy - array creation routines

New ndarray objects can be constructed by any of the following array creation routines or using the low-level ndarray constructor.

numpy.empty method creates uninitialized array

It creates an uninitialized array of the specified shape and dtype. It uses the following constructors:

numpy.empty(shape, dtype = float, order = 'C')

The constructor accepts the following parameters:

serial number Parameters and description
shape shape of the empty array, integer or tuple of integers
dtype desired output array type, optional
order 'C' is a C-style array by row, 'F' is a Fortran-style array by column

example

The following code shows an example of an empty array:

import numpy as np 
x = np.empty([3,2], dtype =  int)   # 创建未初始化的数组
print (x)

#输出如下:		因为未被初始化,所以
[[1701336096 1634235168]
 [1864394096 1752440934]
 [1701716069 1918967927]]

Note: Array elements are random values ​​because they are not initialized.

numpy.zeros 创建用0初始化的数组

返回特定大小,以 0 填充的新数组。

numpy.zeros(shape, dtype = float, order = 'C')

构造器接受下列参数:同numpy.empty方法

示例 1 np.zeros()默认:dtype = float

# 含有 5 个 0 的数组,默认类型为 float  
import numpy as np 

x = np.zeros(5)    # 默认:dtype = float
print (x)

# 输出如下:
[ 0.  0.  0.  0.  0.]

示例 2

import numpy as np 
x = np.zeros((5,), dtype = np.int)  
print x
输出如下:

[0  0  0  0  0]

示例 3 np.zeros() dtype的自定义类型

# 自定义类型 
import numpy as np 
x = np.zeros((2,2), dtype =  [('x',  'i4'),  ('y',  'i4')])   #笔记:元素自定义类型,一个元素有2组变量 名称为x的一组,y为另一组
print (x)
print(x['x'])     # 元素的名称输出

# 输出如下:
[[(0,0)(0,0)]     	# print (x)
 [(0,0)(0,0)]]         
[[0 0]				# print(x['x'])     # 元素的名称输出
 [0 0]] 

numpy.ones() 创建初始值为1的数组

返回特定大小,以 1 填充的新数组。

numpy.ones(shape, dtype = None, order = 'C')

构造器接受下列参数:同np.zeros() 和np.empty()

笔记:numpy.ones()方法的dtype属性默认值为float(测试验证),此处于np.zeros() 和np.empty()相同。

示例 1 numpy.ones()的dtype属性默认值为float

# 含有 5 个 1 的数组,默认类型为 float  
import numpy as np 
x = np.ones(5)  
print(x)

#输出如下:
[ 1.  1.  1.  1.  1.]

示例 2

import numpy as np 
x = np.ones([2,2], dtype =  int)  
print(x)

# 输出如下:
[[1  1] 
 [1  1]]

NumPy - 来自现有数据的数组

这一章中,我们会讨论如何从现有数据创建数组。

numpy.asarray() - Python 序列转换为ndarray非常有用

此函数类似于numpy.array,除了它有较少的参数。 这个例程对于将 Python 序列转换为ndarray非常有用

numpy.asarray(a, dtype = None, order = None)

构造器接受下列参数:

  1. a
    任意形式的输入参数,比如列表列表的元组元组元组的元组元组的列表
  2. dtype
    通常,输入数据的类型会应用到返回的ndarray
  3. order
    'C’为按行的 C 风格数组,'F’为按列的 Fortran 风格数组

下面的例子展示了如何使用asarray函数:

示例 1 list 转 ndarray

# 将列表转换为 ndarray 
import numpy as np 
 
x =  [1,2,3]       # python list
a = np.asarray(x)  
print(a)

# 输出如下:
[1  2  3] 

示例 2 转变元素类型

# 设置了 dtype  
import numpy as np 
 
x =  [1,2,3] 
a = np.asarray(x, dtype =  float)  
print a

# 输出如下:
[ 1.  2.  3.] 

示例 3 tuple 转 ndarray

# 来自元组的 ndarray  
import numpy as np 
 
x =  (1,2,3) 
a = np.asarray(x)  
print(a)

# 输出如下:
[1  2  3]

示例 4 元组的列表 转 ndarray

# 来自元组列表的 ndarray
import numpy as np 
 
x =  [(1,2,3),(4,5)] 
a = np.asarray(x)  
print a

# 输出如下:
[(1, 2, 3) (4, 5)]

numpy.frombuffer() - 将缓冲区解释为一维数组

此函数将缓冲区解释为一维数组暴露缓冲区接口的任何对象都用作参数来返回ndarray

numpy.frombuffer(buffer, dtype = float, count = -1, offset = 0)

构造器接受下列参数:

序号 参数及描述

  1. buffer
    任何暴露缓冲区接口的对象 笔记:开辟内存对象或者数组
  2. dtype
    返回数组的数据类型,默认为float
  3. count
    需要读取的数据数量,默认为-1,读取所有数据
  4. offset
    需要读取的起始位置,默认为0

示例1

下面的例子展示了frombuffer函数的用法。

import numpy as np 
s =  'Hello World' 
a = np.frombuffer(s, dtype = 'S1')  
print(a)

# 输出如下:
['H'  'e'  'l'  'l'  'o'  ' '  'W'  'o'  'r'  'l'  'd']

示例2

import numpy as np 
...

img_buff = (c_ubyte * st_convert_param.nDstBufferSize)()    # 创建c_ubyte类型图像缓存区
cdll.msvcrt.memcpy(byref(img_buff), st_convert_param.pDstBuffer, st_convert_param.nDstBufferSize)   # 为图像缓冲区赋值

# img_buff 转为 numpy类型
img_buff = numpy.frombuffer(img_buff, count=int(st_convert_param.nDstBufferSize), dtype=numpy.uint8)

# 重构
img_buff = img_buff.reshape((frame_info.nHeight, frame_info.nWidth))
...

numpy.fromiter() 可迭代对象构建ndarray对象

此函数从任何可迭代对象构建一个ndarray对象,返回一个新的一维数组。

numpy.fromiter(iterable, dtype, count = -1)

构造器接受下列参数:

  1. iterable
    任何可迭代对象
  2. dtype
    返回数组的数据类型
  3. count
    需要读取的数据数量,默认为-1,读取所有数据

以下示例展示了如何使用内置的range()函数返回列表对象。 此列表的迭代器用于形成ndarray对象。

示例 1 使用 range 函数创建列表对象

# 使用 range 函数创建列表对象  
import numpy as np 
list = range(5)  
print list

# 输出如下:
[0,  1,  2,  3,  4]

示例 2 使用迭代器创建 ndarray

# 从列表中获得迭代器  
import numpy as np 
list = range(5) 
it = iter(list)    # 创建迭代器
# 使用迭代器创建 ndarray 
x = np.fromiter(it, dtype =  float)  
print(x)

# 输出如下:
[0.   1.   2.   3.   4.]

NumPy - 来自数值范围的数组

这一章中,我们会学到如何从数值范围创建数组。

numpy.arange() 生成范围内等间隔值 ndarray对象

这个函数返回ndarray对象,包含给定范围内的等间隔值。

numpy.arange(start, stop, step, dtype)

构造器接受下列参数:

  1. start
    范围的起始值,默认为0
  2. stop
    范围的终止值(不包含)
  3. step
    两个值的间隔,默认为1
  4. dtype
    返回ndarray的数据类型,如果没有提供,则会使用输入数据的类型。

下面的例子展示了如何使用该函数:

示例 1

import numpy as np
x = np.arange(5)  
print(x)

# 输出如下:
[0  1  2  3  4]

示例 2

import numpy as np
# 设置了 dtype
x = np.arange(5, dtype =  float)  
print(x)

# 输出如下:
[0.  1.  2.  3.  4.]

示例 3

# 设置了起始值和终止值参数  
import numpy as np
x = np.arange(10,20,2)  
print(x)
# 输出如下:

[10  12  14  16  18]

numpy.linspace() 类似于arange()函数

此函数类似于arange()函数。 在此函数中,指定了范围之间的均匀间隔数量,而不是步长。 此函数的用法如下。
笔记:linspace()的特点是 均匀间隔,也就是说不需要设置步长,设置中间有多少个数(均匀间隔数量)就可以了。

numpy.linspace(start, stop, num, endpoint, retstep, dtype)

构造器接受下列参数:

  1. start
    序列的起始值
  2. stop
    序列的终止值,如果endpoint为true,该值包含于序列中
  3. num
    要生成的等间隔样例数量,默认为50
  4. endpoint
    序列中是否包含stop值,默认为ture
  5. retstep
    如果为true,返回样例,以及连续数字之间的步长
  6. dtype
    输出ndarray的数据类型,默认类型float

下面的例子展示了linspace函数的用法。

示例 1 均匀间隔

import numpy as np
x = np.linspace(10,20,5)      # 默认endpoint = true, 包含终止值20; 默认dtype=float
print x

# 输出如下:
[10.   12.5   15.   17.5  20.]

示例 2

# 将 endpoint 设为 false
import numpy as np
x = np.linspace(10, 20,  5, endpoint =  False)    # 不包含最后一个数20
print(x)

# 输出如下:
[10.   12.   14.   16.   18.]

示例 3 输出 retstep 值,即:输出步长

笔记:步长是等距间隔,不需要人工输出,但是将 retstep = True,可以输出该步长。

# 输出 retstep 值  
import numpy as np
 
x = np.linspace(1,2,5, retstep =  True)  
print x
# 这里的 retstep 为 0.25
# 输出如下:
(array([ 1.  ,  1.25,  1.5 ,  1.75,  2.  ]), 0.25)

numpy.logspace 对数刻度均匀分布

此函数返回一个ndarray对象,其中包含在对数刻度上均匀分布的数字。 刻度的开始和结束端点是某个底数的幂,通常为 10。

numpy.logscale(start, stop, num, endpoint, base, dtype)

logspace函数的输出由以下参数决定:

  1. start
    起始值是base ** start
  2. stop
    终止值是base ** stop
  3. num
    范围内的数值数量,默认为50
  4. endpoint
    如果为true,终止值包含在输出数组当中
  5. base
    对数空间的底数,默认为10
  6. dtype
    输出数组的数据类型,如果没有提供,则取决于其它参数

下面的例子展示了logspace函数的用法。

示例 1

import numpy as np
# 默认底数是 10
a = np.logspace(1.0,  2.0, num =  10)  
print a

# 输出如下:
[ 10.           12.91549665     16.68100537      21.5443469  27.82559402      
  35.93813664   46.41588834     59.94842503      77.42636827    100.    ]

示例 2

# 将对数空间的底数设置为 2  
import numpy as np
a = np.logspace(1,10,num =  10,  base  =  2)  
print a
# 输出如下:

[ 2.     4.     8.    16.    32.    64.   128.   256.    512.   1024.]

NumPy - 切片和索引

ndarray对象的内容可以通过索引或切片访问和修改,就像 Python 的内置容器对象一样。

如前所述,ndarray对象中的元素遵循基于零的索引
有三种可用的索引方法类型:

  1. 字段访问
  2. 基本切片
  3. 高级索引

基本切片 slice()

基本切片是 Python 中基本切片概念到 n 维的扩展。 通过将start,stop和step参数提供给内置的slice函数来构造一个 Python slice对象。 此slice对象被传递给数组来提取数组的一部分。

示例 1 设置切片范围slice()

import numpy as np

a = np.arange(10)   # [0 1 2 3 4 5 6 7 8 9]
s = slice(2,7,2)    # 创造切片。参数:起始,终止和步长  
print a[s]          # 获得a的s切片

# 输出如下:
[2  4  6]

在上面的例子中,ndarray对象由arange()函数创建。
然后,分别用起始,终止和步长值2,7和2定义切片对象。 当这个切片对象传递给ndarray时,会对它的一部分进行切片,从索引2到7,步长为2。

通过将由冒号分隔的切片参数(start:stop:step)直接提供给ndarray对象,也可以获得相同的结果。

示例 2 直接切片 - 切片参数(start:stop:step)

import numpy as np
a = np.arange(10)
b = a[2:7:2]      # 等效于 s = slice(2,7,2)    a[s]
				  # [起始:终止:步长]    可以只写需要的部分
print b

# 输出如下:
[2  4  6]

如果只输入一个参数,则将返回与索引对应的单个项目。 如果使用a:,则从该索引向后的所有项目将被提取。 如果使用两个参数(以:分隔),则对两个索引(不包括停止索引)之间的元素以默认步骤进行切片。

示例 3 对单个元素进行切片

# 对单个元素进行切片  
import numpy as np
 
a = np.arange(10)
b = a[5]  
print b

# 输出如下:
5

示例 4 只包含起始的切片[start:]

# 对始于索引的元素进行切片  
import numpy as np
a = np.arange(10)  
print a[2:]

# 输出如下:
[2  3  4  5  6  7  8  9]

示例 5 包含起始和终止的切片[start:end]

# 对索引之间的元素进行切片  
import numpy as np
a = np.arange(10)  
print a[2:5]
# 输出如下:
[2  3  4]

上面的描述也可用于多维ndarray。

示例 6 多维数组切片

import numpy as np
a = np.array([[1,2,3],[3,4,5],[4,5,6]])  
print(a)
# 对始于索引的元素进行切片  
print  '现在我们从索引 a[1:] 开始对数组切片'  
print (a[1:])
# 输出如下:   # print(a)
[[1 2 3]    
 [3 4 5]
 [4 5 6]]
 现在我们从索引 a[1:] 开始对数组切片 
# print (a[1:])      
[[3 4 5]
 [4 5 6]]

笔记:在多维数组切片时,第一维切片例如a[1:] 中1表示切片第一维数组的第二个元素值开始至最后一个元素;那么第二维切片怎么表示呢?
第二维切片,例如a[…,1]中“逗号”后面的1表示第二维度数组的第二个元素。由此可见,**“逗号”**是区分维度的关键。再例如a[…,1:]因为1后面多了“:”则表示第二维度数组的第二个元素开始至最后一个元素;

切片还可以包括省略号(…),来使选择元组的长度与数组的维度相同。 如果在行位置使用省略号,它将返回包含行中元素的ndarray。

示例 7 多维数组切片

# 最开始的数组  
import numpy as np
a = np.array([[1,2,3],[3,4,5],[4,5,6]])  
print  '我们的数组是:'  
print a
print  '\n'  
# 这会返回第二列元素的数组:  
print  '第二列的元素是:'  
print a[...,1]              # 切片包含省略号(...),来使选择元组的长度与数组的维度相同。
print  '\n'  
# 现在我们从第二行切片所有元素:  
print  '第二行的元素是:'  
print a[1,...]  
print  '\n'  
# 现在我们从第二列向后切片所有元素:
print  '第二列及其剩余元素是:'  
print a[...,1:]

#输出如下:
 
我们的数组是:  # print(a)
[[1 2 3]
 [3 4 5]
 [4 5 6]]
 
第二列的元素是:  # print a[...,1] 
[2 4 5]
 
第二行的元素是:  # print a[1,...]  
[3 4 5]
 
第二列及其剩余元素是:
[[2 3]
 [4 5]
 [5 6]]

NumPy - 高级索引

如果一个ndarray是非元组序列,数据类型为整数或布尔值的ndarray,或者至少一个元素为序列对象的元组,我们就能够用它来索引ndarray。高级索引始终返回数据的副本。 与此相反,切片只提供了一个视图。

有两种类型的高级索引:

  1. 整数
  2. 布尔值

整数索引

这种机制有助于基于 N 维索引来获取数组中任意元素。 每个整数数组表示该维度的下标值。 当索引的元素个数就是目标ndarray的维度时,会变得相当直接。

以下示例获取了ndarray对象中每一行指定列的一个元素。 因此,行索引包含所有行号,列索引指定要选择的元素。

示例 1 高级索引之二维下标矩阵

笔记:此种方法获得一维数组

import numpy as np 
 
x = np.array([[1,  2],  [3,  4],  [5,  6]]) 
y = x[[0,1,2],  [0,1,0]]     
'''
笔记:理解下标矩阵
[[0,1,2],  [0,1,0]]  组成了一个二维下标矩阵
[0,1,2] 为第一维下标队列
[0,1,0] 为第二维下标队列
组合为矩阵后,列1为 第一维下标队列,列2为 第二维下标队列
(0,0)
(1,1)
(2,0)
'''
print y
# 输出如下:

[1  4  5]   # 获得的是一维数组

该结果包括数组中(0,0),(1,1)和(2,0)位置处的元素。

下面的示例获取了 4X3 数组中的每个角处的元素。 行索引是[0,0]和[3,3],而列索引是[0,2]和[0,2]。

示例 2 行下标矩阵与列下标矩阵

笔记:此种方法获得二维数组

import numpy as np 
x = np.array([[  0,  1,  2],[  3,  4,  5],[  6,  7,  8],[  9,  10,  11]])  
print  ('我们的数组是:')  
print (x) 
print  ('\n') 
rows = np.array([[0,0],[3,3]]) 
cols = np.array([[0,2],[0,2]]) 
y = x[rows,cols]  
'''
笔记:理解行列下标矩阵
rows获得据矩阵为
0,0
3,3
cols获得的矩阵为
0,2
0,2
[rows,cols]  获得矩阵为:
[0,0],[0,2]
[3,0],[3,2]
'''
print  '这个数组的每个角处的元素是:'  
print y

# 输出如下:
我们的数组是:                                                                 
[[ 0  1  2]                                                                   
 [ 3  4  5]                                                                   
 [ 6  7  8]                                                                   
 [ 9 10 11]]
 
这个数组的每个角处的元素是:                                      
[[ 0  2]                                                                      
 [ 9 11]] 

返回的结果是包含每个角元素的ndarray对象。

高级和基本索引可以通过使用切片:或省略号…索引数组组合。 以下示例使用slice作为列索引和高级索引。 当切片用于两者时,结果是相同的。 但高级索引会导致复制,并且可能有不同的内存布局

示例 3 使用slice作为列索引和高级索引

import numpy as np 

x = np.array([[  0,  1,  2],[  3,  4,  5],[  6,  7,  8],[  9,  10,  11]])  # 二维数组
print  '我们的数组是:'  
print x 
print  '\n'  
# 切片
z = x[1:4,1:3]  					# 切片 写法
print  '切片之后,我们的数组变为:'  
print z 
print  '\n'  
# 对列使用高级索引 
y = x[1:4,[1,2]] 					# 高级索引 写法
print  '对列使用高级索引来切片:'  
print y

# 输出如下:

我们的数组是:
[[ 0  1  2] 
 [ 3  4  5] 
 [ 6  7  8]
 [ 9 10 11]]
 
切片之后,我们的数组变为:
[[ 4  5]
 [ 7  8]
 [10 11]]
 
对列使用高级索引来切片:
[[ 4  5]
 [ 7  8]
 [10 11]] 

笔记:
切片和高级索引的区别:
切片是连续的,而高级索引可以不是连续的。因此,高级所以更灵活。
切片和高级索引的相同点:
切片可以获得一维数组,也可以切片多维数组。
高级索引同样可以获得一维数组,也可以获得多维数组。

布尔索引

当结果对象是布尔运算(例如比较运算符)的结果时,将使用此类型的高级索引

示例 1 一维布尔索引

这个例子中,大于 5 的元素会作为布尔索引的结果返回。

import numpy as np 
x = np.array([[  0,  1,  2],[  3,  4,  5],[  6,  7,  8],[  9,  10,  11]])  
print  '我们的数组是:'  
print x 
print  '\n'  
# 现在我们会打印出大于 5 的元素  
print  '大于 5 的元素是:'  
print x[x >  5]      			# 布尔索引  一维布尔索引,比如:[x > 5] 

#输出如下: 
我们的数组是:
[[ 0  1  2] 
 [ 3  4  5] 
 [ 6  7  8] 
 [ 9 10 11]] 
 
大于 5 的元素是:
[ 6  7  8  9 10 11] 

示例 2

这个例子使用了~(取补运算符)来过滤NaN。
笔记:nan(NAN,Nan): not a number 表示不是一个数字,np.nan是一个float类型的数据

import numpy as np 

a = np.array([np.nan, 1, 2, np.nan, 3,4,5])     # 笔记:array的参数[np.nan, 1, 2, np.nan, 3,4,5]是一个列表,由2个非数字(np.nan)和5个数字组成
print a[~np.isnan(a)]    # 笔记:np.isnan(a) 判断是否为非数字,~np.isnan(a)表示是否为数字

# 输出如下:
[ 1.   2.   3.   4.   5.] 

示例 3

以下示例显示如何从数组中过滤掉非复数元素

import numpy as np 
a = np.array([1,  2+6j,  5,  3.5+5j])  
print a[np.iscomplex(a)]

#输出如下:
[2.0+6.j  3.5+5.j] 

NumPy - 广播

术语广播是指 NumPy 在算术运算期间处理不同形状的数组的能力。 对数组的算术运算通常在相应的元素上进行。 如果两个阵列具有完全相同的形状,则这些操作被无缝执行。

笔记:广播 是 对不同形状的数组(shape)进行数值计算的方式,对数组的算术运算通常在响应的元素上进行。

示例 1 - 2组数量相同的队列 相乘

import numpy as np 
 
a = np.array([1,2,3,4]) 
b = np.array([10,20,30,40]) 
c = a * b 
print c

# 输出如下:
[10   40   90   160]

形状相同
如果两个数组a和b形状相同,即:a.shape() == b.shape(),那么a+b的结果就是a与b数组对应位元素相加。要求,维度相同,且对应维度的长度相同。
形状不同
如果两个数组的维数不相同,则元素到元素的操作不可能的。 然而,在 NumPy 中仍然可以对形状不相似的数组进行操作,因为它拥有广播功能
较小的数组会广播到较大数组的大小,以便使它们的形状可兼容。

如果满足以下规则,可以进行广播:

  1. ndim较小的数组会在前面追加一个长度为 1 的维度。
  2. 输出数组的每个维度的大小是输入数组维度大小的最大值
  3. 如果输入在每个维度中的大小与输出大小匹配,或其值正好为 1,则在计算中可它。
  4. 如果输入的某个维度大小为 1,则该维度中的第一个数据元素将用于该维度的所有计算。

如果上述规则产生有效结果,并且满足以下条件之一,那么数组被称为可广播的

  1. 数组拥有相同形状。
  2. 数组拥有相同的维数,每个维度拥有相同长度,或者长度为 1
  3. 数组拥有极少的维度,可以在其前面追加长度为 1 的维度,使上述条件成立。

笔记:ndim中的dim是英文dimension维度的缩写。ndim是数组轴(维度)的个数。

下面的例称展示了广播的示例。

示例 2 广播 两个数组相加

import numpy as np 
a = np.array([[0.0,0.0,0.0],[10.0,10.0,10.0],[20.0,20.0,20.0],[30.0,30.0,30.0]]) 
b = np.array([1.0,2.0,3.0])  
print  '第一个数组:'  
print a 
print  '\n'  
print  '第二个数组:'  
print b 
print  '\n'  
print  '第一个数组加第二个数组:'  
print a + b

# 输出如下:
第一个数组:
[[ 0. 0. 0.]
 [ 10. 10. 10.]
 [ 20. 20. 20.]
 [ 30. 30. 30.]]
 
第二个数组:
[ 1. 2. 3.]
 
第一个数组加第二个数组:
[[ 1. 2. 3.]
 [ 11. 12. 13.]
 [ 21. 22. 23.]
 [ 31. 32. 33.]]

下面的图片展示了数组b如何通过广播来与数组a兼容。

insert image description here
笔记:b数组维度小,并且可以追加一个长度为 1 的维度。

NumPy - 数组上的迭代

NumPy 包包含一个迭代器对象numpy.nditer。 它是一个有效的多维迭代器对象,可以用于在数组上进行迭代。 数组的每个元素可使用 Python 的标准Iterator接口来访问。

迭代器对象numpy.nditer

让我们使用arange()函数创建一个 3X4 数组,并使用nditer对它进行迭代。

示例 1 numpy.nditer(a)迭代器对象

import numpy as np

a = np.arange(0,60,5)    # 0 至 59 步长5
a = a.reshape(3,4)       # 也可以利用属性  a.shape(3,4)
print  '原始数组是:'  
print a print  '\n'  
print  '修改后的数组是:'  
for x in np.nditer(a):  	# x 为numpy.nditer迭代器对象
    print x,

# 输出如下: 
原始数组是:
[[ 0 5 10 15]
 [20 25 30 35]
 [40 45 50 55]]
 
修改后的数组是:
0 5 10 15 20 25 30 35 40 45 50 55

示例 2 迭代的顺序匹配数组的内容布局

迭代的顺序匹配数组的内容布局,而不考虑特定的排序(参照下例理解,转换后,迭代器输出不变)。 这可以通过迭代上述数组的转置来看到。

import numpy as np 
a = np.arange(0,60,5) 
a = a.reshape(3,4)  
print  '原始数组是:'  
print a 
print  '\n'  
print  '原始数组的转置是:' 
b = a.T 			# 矩阵的置换  可以理解为以00,nn连线为轴的镜像操作
print b 
print  '\n'  
print  '修改后的数组是:'  
for x in np.nditer(b):      # 笔记:转换后,迭代器输出不变。
    print x,
输出如下:

 
原始数组是:
[[ 0 5 10 15]
 [20 25 30 35]
 [40 45 50 55]]
 
原始数组的转置是:
[[ 0 20 40]
 [ 5 25 45]
 [10 30 50]
 [15 35 55]]
 
修改后的数组是:
0 5 10 15 20 25 30 35 40 45 50 55

笔记: b = a.T 其中a.T为 转置变换。元素[0,0]、元素[m,n]保持不变,其他元素行列颠倒。

迭代顺序

如果相同元素使用 F 风格顺序存储,则迭代器选择以更有效的方式对数组进行迭代。
笔记: 所谓风格,即order参数; C(按行)、F(按列)或A(任意,默认);order的风格 影响 迭代器的输出顺序

示例 1 order风格 影响 迭代器的顺序

import numpy as np
a = np.arange(0,60,5) 
a = a.reshape(3,4)  
print  '原始数组是:'  
print a 
print  '\n'  
print  '原始数组的转置是:' 
b = a.T 
print b 
print  '\n'  
print  '以 C 风格顺序排序:' 
c = b.copy(order='C')  
print c for x in np.nditer(c):  
    print x,  
print  '\n'  
print  '以 F 风格顺序排序:' 
c = b.copy(order='F')  
print c 
for x in np.nditer(c):  			# order 分隔影响 迭代器的顺序
    print x,

# 输出如下:
原始数组是:
[[ 0 5 10 15]
 [20 25 30 35]
 [40 45 50 55]]
 
原始数组的转置是:
[[ 0 20 40]
 [ 5 25 45]
 [10 30 50]
 [15 35 55]]
 
以 C 风格顺序排序:  # C风格:按行排序
[[ 0 20 40]
 [ 5 25 45]
 [10 30 50]
 [15 35 55]]
0 20 40 5 25 45 10 30 50 15 35 55
 
以 F 风格顺序排序: # F风格:按列排序
[[ 0 20 40]
 [ 5 25 45]
 [10 30 50]
 [15 35 55]]
0 5 10 15 20 25 30 35 40 45 50 55

示例 2 强制nditer对象使用某种顺序

可以通过显式提醒,来强制nditer对象使用某种顺序:

import numpy as np 
a = np.arange(0,60,5) 
a = a.reshape(3,4)  
print  '原始数组是:'  
print a 
print  '\n'  
print  '以 C 风格顺序排序:'  
for x in np.nditer(a, order =  'C'):    # 强制规定迭代器风格   C-行
    print x,  
print  '\n'  
print  '以 F 风格顺序排序:'  
for x in np.nditer(a, order =  'F'):  
    print x,

# 输出如下:
原始数组是:
[[ 0 5 10 15]
 [20 25 30 35]
 [40 45 50 55]]
 
以 C 风格顺序排序:
0 5 10 15 20 25 30 35 40 45 50 55
 
以 F 风格顺序排序:
0 20 40 5 25 45 10 30 50 15 35 55

修改数组的值

nditer对象有另一个可选参数op_flags。 其默认值为只读,但可以设置为读写只写模式。 这将允许使用此迭代器修改数组元素。

示例1 修改数组值

import numpy as np
a = np.arange(0,60,5) 
a = a.reshape(3,4)  
print  '原始数组是:'  
print a 
print  '\n'  
for x in np.nditer(a, op_flags=['readwrite']):    	# 修改迭代器为 读写
    x[...]=2*x 										# 笔记:x[...] 这个写法没有理解??
print  '修改后的数组是:'  
print a
# 输出如下:

 
原始数组是:
[[ 0 5 10 15]
 [20 25 30 35]
 [40 45 50 55]]
 
修改后的数组是:
[[ 0 10 20 30]
 [ 40 50 60 70]
 [ 80 90 100 110]]

小实验 证明a.T没有创建新的数组

import numpy as np
a = np.arange(0,60,5) 
a = a.reshape(3,4)  
print  ('原始数组是:'  )
print (a) 
print  ('\n' ) 
b = a.T    # 颠倒
for x in np.nditer(a, op_flags=['readwrite']):    # 修改迭代器为 读写
    x[...]=2*x 
print ('修改后的数组是:'  )
print (a)
print("b = ")
print(b)

#输出结果
原始数组是:
[[ 0  5 10 15]
 [20 25 30 35]
 [40 45 50 55]]


修改后的数组是:
[[  0  10  20  30]
 [ 40  50  60  70]
 [ 80  90 100 110]]
b = 
[[  0  40  80]
 [ 10  50  90]
 [ 20  60 100]
 [ 30  70 110]]

笔记:b = a.T 位于修改a数组值之前,但是输出b时,b的元素值也被改变了。这说明,b = a.T 并没有 创建新的数组,而是执行了a所开辟的内存,只是显示顺序改变了而已。

外部循环

nditer类的构造器拥有flags参数,它可以接受下列值:

  1. c_index 可以跟踪 C 顺序的索引 (行顺序)
  2. f_index 可以跟踪 Fortran 顺序的索引 (列顺序)
  3. multi-index 每次迭代可以跟踪一种索引类型
  4. external_loop 给出的值是具有多个值的一维数组,而不是零维数组

示例

在下面的示例中,迭代器遍历对应于每列的一维数组。

import numpy as np 
a = np.arange(0,60,5) 
a = a.reshape(3,4)  
print  '原始数组是:'  
print a 
print  '\n'  
print  '修改后的数组是:'  
for x in np.nditer(a, flags =  ['external_loop'], order =  'F'):  
    print x,

# 输出如下: 
原始数组是:
[[ 0 5 10 15]
 [20 25 30 35]
 [40 45 50 55]]
 
修改后的数组是:
[ 0 20 40] [ 5 25 45] [10 30 50] [15 35 55]    # 给出的值是具有**多个值的一维数组**,而不是零维数组

广播迭代

如果两个数组是可广播的(笔记:数组间的加减乘除运算),nditer组合对象能够同时迭代它们。 假设数组a具有维度 3X4,并且存在维度为 1X4 的另一个数组b,则使用以下类型的迭代器(数组b被广播到a的大小)。

示例

import numpy as np 
a = np.arange(0,60,5) 
a = a.reshape(3,4)  
print  '第一个数组:'  
print a 
print  '\n'  
print  '第二个数组:' 
b = np.array([1,  2,  3,  4], dtype =  int)  
print b 
print  '\n'  
print  '修改后的数组是:'  
for x,y in np.nditer([a,b]):    # 迭代器广播
    print  "%d:%d"  %  (x,y),

# 输出如下: 
第一个数组:
[[ 0 5 10 15]
 [20 25 30 35]
 [40 45 50 55]]
 
第二个数组:
[1 2 3 4]
 
修改后的数组是:
0:1 5:2 10:3 15:4 20:1 25:2 30:3 35:4 40:1 45:2 50:3 55:4

NumPy - 数组操作

NumPy包中有几个例程用于处理ndarray对象中的元素。 它们可以分为以下类型:

修改形状

  1. reshape() 不改变数据的条件下修改形状
  2. flat 数组上的一维迭代器
  3. flatten 返回折叠为一维的数组副本
  4. ravel 返回连续的展开数组

numpy.reshape()

这个函数在不改变数据的条件下修改形状,它接受如下参数:

numpy.reshape(arr, newshape, order')

其中:

  • arr:要修改形状的数组
  • newshape:整数或者整数数组,新的形状应当兼容原有形状
  • order:'C’为 C 风格顺序,'F’为 F 风格顺序,'A’为保留原顺序。

例子

import numpy as np
a = np.arange(8)
print '原始数组:'
print a
print '\n'
 
b = a.reshape(4,2)     # 可以用 a.reshape(4,2) 也可以用numpy.reshape()函数的形式
print '修改后的数组:'
print b
# 输出如下:

原始数组:
[0 1 2 3 4 5 6 7]
 
修改后的数组:
[[0 1]
 [2 3]
 [4 5]
 [6 7]]

numpy.ndarray.flat()

该函数返回数组上的一维迭代器,行为类似 Python 内建的迭代器。
笔记:不管数组的形状(例如:reshape(2,4)),只将数组作为一维进行迭代。注意,flat()方法属于ndarray类。flat 水平的

例子

import numpy as np 
a = np.arange(8).reshape(2,4)    # 也是一种写法
print '原始数组:' 
print a 
print '\n' 
 
print '调用 flat 函数之后:' 
# 返回展开数组中的下标的对应元素 
print a.flat[5]  				# 不管数组的形状,只将数组作为一维进行迭代。

# 输出如下: 
原始数组:
[[0 1 2 3]
 [4 5 6 7]]
 
调用 flat 函数之后:
5

numpy.ndarray.flatten()

该函数返回折叠为一维的数组副本,函数接受下列参数:

ndarray.flatten(order)

其中:
order:‘C’ – 按行,‘F’ – 按列,‘A’ – 原顺序,‘k’ – 元素在内存中的出现顺序。

例子

import numpy as np 
a = np.arange(8).reshape(2,4) 
 
print('src list') 
print (a) 
print ('\n')  
# default is column-major 
 
print('展开的数组:') 
b = a.flatten() 
print(b)
print('\n')  

print('again src list') 
a[0] = 23
print (a) 
print ('\n')   

print('展开的数组:') 
print(b)


# 输出如下:
src list
[[0 1 2 3]
 [4 5 6 7]]


展开的数组:
[0 1 2 3 4 5 6 7]


again src list
[[23 23 23 23]
 [ 4  5  6  7]]


展开的数组:
[0 1 2 3 4 5 6 7]

笔记:从上例可以看出,副本即一个全新内存块。

numpy.ravel()

这个函数返回展开的一维数组,并且按需生成副本(笔记:一个全新的内存块)。返回的数组和输入数组拥有相同数据类型。这个函数接受两个参数。

numpy.ravel(a, order)

构造器接受下列参数:
a: ndarray数组对象
order:‘C’ – 按行,‘F’ – 按列,‘A’ – 原顺序,‘k’ – 元素在内存中的出现顺序。

例子

import numpy as np 
a = np.arange(8).reshape(2,4) 
 
print '原数组:' 
print a 
print '\n'  
 
print '调用 ravel 函数之后:' 
print a.ravel()  
print '\n' 
 
print '以 F 风格顺序调用 ravel 函数之后:' 
print a.ravel(order = 'F')
 
原数组:
[[0 1 2 3]
 [4 5 6 7]]
 
调用 ravel 函数之后:
[0 1 2 3 4 5 6 7]
 
以 F 风格顺序调用 ravel 函数之后:
[0 4 1 5 2 6 3 7]

翻转操作

  1. transpose 翻转数组的维度
  2. ndarray.T 和 **self.transpose()**相同
  3. rollaxis 向后滚动指定的轴
  4. swapaxes 互换数组的两个轴

numpy.transpose()

这个函数翻转给定数组的维度。如果可能的话它会返回一个视图。函数接受下列参数:
笔记:行、列对调 形成的翻转

numpy.transpose(arr, axes)

其中:

  • arr:要转置的数组
  • axes:整数的列表,对应维度,通常所有维度都会翻转。

例子

import numpy as np 
a = np.arange(12).reshape(3,4) 
 
print '原数组:' 
print a  
print '\n' 
 
print '转置数组:' 
print np.transpose(a)

#输出如下: 
原数组:
[[ 0 1 2 3]
 [ 4 5 6 7]
 [ 8 9 10 11]]
 
转置数组:
[[ 0 4 8]
 [ 1 5 9]
 [ 2 6 10]
 [ 3 7 11]]

numpy.ndarray.T 方法

该函数属于ndarray类,行为类似于numpy.transpose。
笔记:写的时候由于没有参数,因此T不需要加括号

例子

import numpy as np 
a = np.arange(12).reshape(3,4) 
 
print '原数组:' 
print a 
print '\n'  
 
print '转置数组:' 
print a.T     # 写法简单,但是没有numpy.transpose灵活。

# 输出如下:
原数组:
[[ 0 1 2 3]
 [ 4 5 6 7]
 [ 8 9 10 11]]
 
转置数组:
[[ 0 4 8]
 [ 1 5 9]
 [ 2 6 10]
 [ 3 7 11]]

笔记:这种置换,可以理解为在原有一维数组的基础上,调整order属性。即:原ndarray对象.order=‘C’, 调用numpy.ndarray.T 方法 或者 numpy.transpose()后,ndarray对象.order=‘F’。反之亦然。

numpy.rollaxis()

该函数向后滚动特定的轴,直到一个特定位置。这个函数接受三个参数:

numpy.rollaxis(arr, axis, start)

其中:

  • arr:输入数组
  • axis:要向后滚动的轴,其它轴的相对位置不会改变
  • start:默认为0,表示完整的滚动。会滚动到特定位置

笔记:
轴的介绍
例如 a = np.arange(12).reshape(1,2,3)
1表示第一维长度1,第一维即:轴0
2表示第二维长度2,第二维即:轴1
3表示第三维长度3,第三维即:轴2
轴也有如下表示
轴0 深度方向
轴1 高度方向
轴2 宽度方向
轴的滚动
二维滚动
a=np.arrage(12).reshape(3,4)
a.shape = (3,4)
b=np.rollaxis(a,1) # 滚动轴
b.shape = (4,3)

例子

import numpy as np 

a = np.arange(24).reshape(2,3,4) 
 
print("a=", a)
print("a.shape = ", a.shape)
print("\n") 
    
d = np.rollaxis(a,1)  
print("np.rollaxis(a,1) = \n", d)
print("shap = ", d.shape)    
print("\n") 
    
b = np.rollaxis(a,2)  
print("np.rollaxis(a,2) = \n", b)
print("shap = ", b.shape)
print("\n") 

c = np.rollaxis(a,2,1)
print("np.rollaxis(a,2,1) = \n", c)
print("shap = ", c.shape)

# 输出如下:
 
a= [[[ 0  1  2  3]
  [ 4  5  6  7]
  [ 8  9 10 11]]

 [[12 13 14 15]
  [16 17 18 19]
  [20 21 22 23]]]
a.shape =  (2, 3, 4)


np.rollaxis(a,1) =     
 [[[ 0  1  2  3]
  [12 13 14 15]]

 [[ 4  5  6  7]
  [16 17 18 19]]

 [[ 8  9 10 11]
  [20 21 22 23]]]
shap =  (3, 2, 4)   # 轴1 和 轴0 滚动调换


np.rollaxis(a,2) = 
 [[[ 0  4  8]
  [12 16 20]]

 [[ 1  5  9]
  [13 17 21]]

 [[ 2  6 10]
  [14 18 22]]

 [[ 3  7 11]
  [15 19 23]]]
shap =  (4, 2, 3)     # 轴2 和轴1 滚动对调


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

 [[12 16 20]
  [13 17 21]
  [14 18 22]
  [15 19 23]]]
shap =  (2, 4, 3)   # 轴2 和 轴1 滚动对调

numpy.swapaxes()

该函数交换数组的两个轴。对于 1.10 之前的 NumPy 版本,会返回交换后数组的试图。这个函数接受下列参数:

numpy.swapaxes(arr, axis1, axis2)
  • arr:要交换其轴的输入数组
  • axis1:对应第一个轴的整数
  • axis2:对应第二个轴的整数
# 创建了三维的 ndarray 
import numpy as np 
a = np.arange(8).reshape(2,2,2) 
 
print '原数组:'
print a 
print '\n'  
# 现在交换轴 0(深度方向)到轴 2(宽度方向)
 
print '调用 swapaxes 函数后的数组:' 
print np.swapaxes(a, 2, 0)

# 输出如下:

 
原数组:
[[[0 1]
 [2 3]]
 
 [[4 5]
  [6 7]]]
 
调用 swapaxes 函数后的数组:
[[[0 4]
 [2 6]]
 
 [[1 5]
  [3 7]]]

修改维度

笔记:区分修改形状和修改维度。
修改形状是在相同维度下修改形状,例如:a.shape() = (2,3) 修改形状后 a.shape() = (1,6) 。
修改维度则是增加或减少维度。例如:2维 变 3

  1. **broadcast()**产生模仿广播的对象
  2. broadcast_to() 将数组广播到新形状
  3. expand_dims() 扩展数组的形状
  4. squeeze() 从数组的形状中删除单维条目
    笔记:对广播的肤浅理解,广播为一个矩阵对另一个矩阵到操作(加减乘除);由于其中一个矩阵可能很小,只有一维(例如[1:4])。而另一个矩阵可能很大,有2维(例如:[10:4])。从中文字面理解,2个矩阵操作中,1 至 10的操作过程就像广播。

broadcast

如前所述,NumPy 已经内置了对广播的支持。 此功能模仿广播机制。 它返回一个对象,该对象封装了将一个数组广播到另一个数组的结果。

笔记:b = np.broadcast(x,y) x为维度形状模板,将y广播与x形状相同。返回值b 并不是一个ndarray对象,而是一个封装将一个数组广播到另一个数组的结果。比如: b = <numpy.broadcast object at 0x000002274B3F0AA0>
b内包含有x和广播y的结果, 例如:r,c = b.iters r迭代器表示x,c迭代器表示y

该函数使用两个数组作为输入参数。 下面的例子说明了它的用法。

import numpy as np 
x = np.array([[1], [2], [3]])   # 二维数组
y = np.array([4, 5, 6])  		# 一维数组
   
# 对 y 广播 x
b = np.broadcast(x,y)  
# 它拥有 iterator 属性,基于自身组件的迭代器元组 
 
print '对 y 广播 x:' 
r,c = b.iters 
print next(r), next(c) 
print next(r), c.next(c) 
print '\n'  
# shape 属性返回广播对象的形状
 
print '广播对象的形状:' 
print b.shape 
print '\n'  
# 手动使用 broadcast 将 x 与 y 相加
b = np.broadcast(x,y) 
c = np.empty(b.shape) 
 
print '手动使用 broadcast 将 x 与 y 相加:' 
print c.shape 
print '\n'  
c.flat = [u + v for (u,v) in b]   # flat 该函数返回数组上的**一维迭代器**,行为类似 Python 内建的迭代器。
 
print '调用 flat 函数:' 
print c 
print '\n'  
# 获得了和 NumPy 内建的广播支持相同的结果
 
print 'x 与 y 的和:' 
print x + y

# 输出如下:
对 y 广播 x:
1 4
1 5
 
广播对象的形状:
(3, 3)
 
手动使用 broadcast 将 x 与 y 相加:
(3, 3)
 
调用 flat 函数:
[[ 5. 6. 7.]
 [ 6. 7. 8.]
 [ 7. 8. 9.]]
 
x 与 y 的和:
[[5 6 7]
 [6 7 8]
 [7 8 9]]

numpy.broadcast_to

此函数将数组广播到新形状。 它在原始数组上返回只读视图。 它通常不连续。 如果新形状不符合 NumPy 的广播规则,该函数可能会抛出ValueError。

注意 - 此功能可用于 1.10.0 及以后的版本。

该函数接受以下参数。

numpy.broadcast_to(array, shape, subok)

例子

import numpy as np 
a = np.arange(4).reshape(1,4) 
 
print '原数组:' 
print a 
print '\n'  
 
print '调用 broadcast_to 函数之后:' 
print np.broadcast_to(a,(4,4))

# 输出如下:
[[0  1  2  3] 
 [0  1  2  3] 
 [0  1  2  3] 
 [0  1  2  3]]

numpy.expand_dims

函数通过在指定位置插入新的轴来扩展数组形状。该函数需要两个参数:

numpy.expand_dims(arr, axis)   # axis 轴

其中:

  • arr:输入数组
  • axis:新轴插入的位置

例子

import numpy as np 
x = np.array(([1,2],[3,4])) 
 
print '数组 x:' 
print x 
print '\n'  
y = np.expand_dims(x, axis = 0) 
 
print '数组 y:' 
print y 
print '\n'
 
print '数组 x 和 y 的形状:' 
print x.shape, y.shape 
print '\n'  
# 在位置 1 插入轴
y = np.expand_dims(x, axis = 1) 
 
print '在位置 1 插入轴之后的数组 y:' 
print y 
print '\n'  
 
print 'x.ndim 和 y.ndim:' 
print x.ndim,y.ndim 
print '\n'  
 
print 'x.shape 和 y.shape:' 
print x.shape, y.shape

输出如下:

 
数组 x:
[[1 2]
 [3 4]]
 
数组 y:
[[[1 2]
 [3 4]]]
 
数组 x 和 y 的形状:
(2, 2) (1, 2, 2)
 
在位置 1 插入轴之后的数组 y:
[[[1 2]]
 [[3 4]]]
 
x.ndim 和 y.ndim:
2 3
 
x.shape and y.shape:
(2, 2) (2, 1, 2)

numpy.squeeze

函数从给定数组的形状中删除一维条目。 此函数需要两个参数。

numpy.squeeze(arr, axis)

其中:

  • arr:输入数组
  • axis:整数或整数元组,用于选择形状中单一维度条目的子集

例子

import numpy as np  
x = np.arange(9).reshape(1,3,3) 
 
print '数组 x:' 
print x 
print '\n'  
y = np.squeeze(x) 
 
print '数组 y:' 
print y 
print '\n'  
 
print '数组 x 和 y 的形状:' 
print x.shape, y.shape

输出如下:

 
数组 x:
[[[0 1 2]
 [3 4 5]
 [6 7 8]]]
 
数组 y:
[[0 1 2]
 [3 4 5]
 [6 7 8]]
 
数组 x 和 y 的形状:
(1, 3, 3) (3, 3)

数组的连接

  1. concatenate 沿着现存的轴连接数据序列
  2. stack 沿着新轴连接数组序列
  3. hstack 水平堆叠序列中的数组(列方向
  4. vstack 竖直堆叠序列中的数组(行方向

numpy.concatenate

此函数用于沿指定轴连接相同形状的两个或多个数组。 该函数接受以下参数。
笔记:连接的前提形状相同。

numpy.concatenate((a1, a2, ...), axis)

其中:

  • a1, a2, …:相同类型的数组序列
  • axis:沿着它连接数组的轴,默认为 0

例子

import numpy as np 
a = np.array([[1,2],[3,4]])  # 一行两列 
 
print '第一个数组:' 
print a 
print '\n'  
b = np.array([[5,6],[7,8]])   # 一行两列
 
print '第二个数组:' 
print b 
print '\n'  
# 两个数组的维度相同 
 
print '沿轴 0 连接两个数组:' 
print np.concatenate((a,b))   # 轴0 一行
print '\n'  
 
print '沿轴 1 连接两个数组:' 
print np.concatenate((a,b),axis = 1)   # 轴1  列

输出如下:

 
第一个数组:
[[1 2]
 [3 4]]
 
第二个数组:
[[5 6]
 [7 8]]
 
沿轴 0 连接两个数组:
[[1 2]
 [3 4]
 [5 6]
 [7 8]]
 
沿轴 1 连接两个数组:
[[1 2 5 6]
 [3 4 7 8]]

numpy.stack

此函数沿新轴连接数组序列。 此功能添加自 NumPy 版本 1.10.0。 需要提供以下参数。

numpy.stack(arrays, axis)

其中:

  • arrays:相同形状的数组序列
  • axis:返回数组中的轴,输入数组沿着它来堆叠
import numpy as np 

a = np.array([[1,2],[3,4]])  
print '第一个数组:' 
print a 
print '\n'

b = np.array([[5,6],[7,8]])  
print '第二个数组:' 
print b 
print '\n'  
 
print '沿轴 0 堆叠两个数组:' 
print np.stack((a,b),0) 
print '\n'  
 
print '沿轴 1 堆叠两个数组:' 
print np.stack((a,b),1)

# 输出如下:

 
第一个数组:
[[1 2]
 [3 4]]
 
第二个数组:
[[5 6]
 [7 8]]
 
沿轴 0 堆叠两个数组:
[[[1 2]
 [3 4]]
 [[5 6]
 [7 8]]]
 
沿轴 1 堆叠两个数组:
[[[1 2]
 [5 6]]
 [[3 4]
 [7 8]]]

numpy.hstack

numpy.stack函数的变体,通过堆叠来生成水平的单个数组。

例子

import numpy as np 
a = np.array([[1,2],[3,4]]) 
 
print '第一个数组:' 
print a 
print '\n'  
b = np.array([[5,6],[7,8]]) 
 
print '第二个数组:' 
print b 
print '\n'  
 
print '水平堆叠:' 
c = np.hstack((a,b)) 
print c 
print '\n'

输出如下:

 
第一个数组:
[[1 2]
 [3 4]]
 
第二个数组:
[[5 6]
 [7 8]]
 
水平堆叠:
[[1 2 5 6]
 [3 4 7 8]]

numpy.vstack

numpy.stack函数的变体,通过堆叠来生成竖直的单个数组。

import numpy as np 
a = np.array([[1,2],[3,4]]) 
 
print '第一个数组:' 
print a 
print '\n'  
b = np.array([[5,6],[7,8]]) 
 
print '第二个数组:' 
print b 
print '\n'
 
print '竖直堆叠:' 
c = np.vstack((a,b)) 
print c

输出如下:

 
第一个数组:
[[1 2]
 [3 4]]
 
第二个数组:
[[5 6]
 [7 8]]
 
竖直堆叠:
[[1 2]
 [3 4]
 [5 6]
 [7 8]]

数组分割

  1. split 将一个数组分割为多个子数组
  2. hsplit 将一个数组水平分割为多个子数组(按列)
  3. vsplit 将一个数组竖直分割为多个子数组(按行)

numpy.split

该函数沿特定的轴将数组分割为子数组。函数接受三个参数:

numpy.split(ary, indices_or_sections, axis)

其中:

  • ary:被分割的输入数组
  • indices_or_sections:可以是整数,表明要从输入数组创建的,等大小的子数组的数量。 如果此参数是一维数组,则其元素表明要创建新子数组的点。
  • axis:默认为 0

例子

import numpy as np 
a = np.arange(9) 
 
print ("a = \n", a) 
 
b = np.split(a,3) 
print ('np.split(a,3) = \n',b)
 
b = np.split(a,[4,7])
print("np.split(a,[4,7]) = \n", b)

# 输出如下:
a = 
 [0 1 2 3 4 5 6 7 8]
np.split(a,3) = 
 [array([0, 1, 2]), array([3, 4, 5]), array([6, 7, 8])]
np.split(a,[4,7]) = 
 [array([0, 1, 2, 3]), array([4, 5, 6]), array([7, 8])]

numpy.hsplit

numpy.hsplit是split()函数的特例,其中轴为 1 表示水平分割,无论输入数组的维度是什么。

import numpy as np 
a = np.arange(16).reshape(4,4) 
 
print '第一个数组:' 
print a 
print '\n'  
 
print '水平分割:' 
b = np.hsplit(a,2) 
print b 
print '\n'

#输出:
第一个数组:
[[ 0 1 2 3]
 [ 4 5 6 7]
 [ 8 9 10 11]
 [12 13 14 15]]
 
水平分割:                                                         
[array([[ 0,  1],                                                             
       [ 4,  5],                                                              
       [ 8,  9],                                                              
       [12, 13]]), 
 array([[ 2,  3],                                           
       [ 6,  7],                                                              
       [10, 11],                                                              
       [14, 15]])] 

numpy.vsplit

numpy.vsplit是split()函数的特例,其中轴为 0 表示竖直分割,无论输入数组的维度是什么。下面的例子使之更清楚。

import numpy as np 
a = np.arange(16).reshape(4,4) 
 
print '第一个数组:' 
print a 
print '\n'
 
print '竖直分割:' 
b = np.vsplit(a,2) 
print b
输出如下:

 
第一个数组:
[[ 0 1 2 3]
 [ 4 5 6 7]
 [ 8 9 10 11]
 [12 13 14 15]]
 
竖直分割:                                                           
[array([[0, 1, 2, 3],                                                         
       [4, 5, 6, 7]]), array([[ 8,  9, 10, 11],                               
       [12, 13, 14, 15]])] 

添加/删除元素

  1. resize 返回指定形状的新数组
  2. append 将值添加到数组末尾
  3. insert 沿指定轴将值插入到指定下标之前
  4. delete 返回删掉某个轴的子数组的新数组
  5. unique 寻找数组内的唯一元素

numpy.resize

此函数返回指定大小的新数组。 如果新大小大于原始大小,则包含原始数组中的元素的重复副本。 该函数接受以下参数。
笔记:np.resize() 与 ndarray.shape() 效果相同

numpy.resize(arr, shape)

其中:

  • arr:要修改大小的输入数组
  • shape:返回数组的新形状

例子

import numpy as np 
a = np.array([[1,2,3],[4,5,6]]) 
 
print '第一个数组:' 
print a 
print '\n'
 
print '第一个数组的形状:' 
print a.shape 
print '\n'  
b = np.resize(a, (3,2)) 
 
print '第二个数组:' 
print b 
print '\n'  
 
print '第二个数组的形状:' 
print b.shape 
print '\n'  
# 要注意 a 的第一行在 b 中重复出现,因为尺寸变大了 
 
print '修改第二个数组的大小:' 
b = np.resize(a,(3,3)) 
print b

输出如下:

 
第一个数组:
[[1 2 3]
 [4 5 6]]
 
第一个数组的形状:
(2, 3)
 
第二个数组:
[[1 2]
 [3 4]
 [5 6]]
 
第二个数组的形状:
(3, 2)
 
修改第二个数组的大小:
[[1 2 3]
 [4 5 6]
 [1 2 3]]

numpy.append

此函数在输入数组的末尾添加值。 附加操作不是原地的,而是分配新的数组。 此外,输入数组的维度必须匹配否则将生成ValueError。
笔记:np.append() 返回 新的数组(分配新的内存)

函数接受下列函数:

numpy.append(arr, values, axis)

其中:

  • arr:输入数组
  • values:要向arr添加的值,比如和arr形状相同(除了要添加的轴)
  • axis:沿着它完成操作的轴。如果没有提供两个参数都会被展开

例子

import numpy as np 
a = np.array([[1,2,3],[4,5,6]]) 
 
print '第一个数组:' 
print a 
print '\n'  
 
print '向数组添加元素:' 
print np.append(a, [7,8,9])   
print '\n'  
 
print '沿轴 0 添加元素:' 
print np.append(a, [[7,8,9]],axis = 0) 
print '\n'  
 
print '沿轴 1 添加元素:' 
print np.append(a, [[5,5,5],[7,8,9]],axis = 1)

#输出如下:
第一个数组:
[[1 2 3]
 [4 5 6]]
 
向数组添加元素:
[1 2 3 4 5 6 7 8 9]
 
沿轴 0 添加元素:
[[1 2 3]
 [4 5 6]
 [7 8 9]]
 
沿轴 1 添加元素:
[[1 2 3 5 5 5]
 [4 5 6 7 8 9]]

numpy.insert

此函数在给定索引之前,沿给定轴在输入数组中插入值。 如果值的类型转换为要插入,则它与输入数组不同。 插入没有原地的,函数会返回一个新数组。 此外,如果未提供轴,则输入数组会被展开。

insert()函数接受以下参数:

numpy.insert(arr, obj, values, axis)

其中:

  • arr:输入数组
  • obj:在其之前插入值的索引
  • values:要插入的值
  • axis:沿着它插入的轴,如果未提供,则输入数组会被展开

例子

import numpy as np 
a = np.array([[1,2],[3,4],[5,6]]) 
 
print ('第一个数组:' )
print (a )
 
print ('未传递 Axis 参数。 在插入之前输入数组会被展开。' )
print (np.insert(a,3,[11,12]) )
print ('\n'  )
print ('传递了 Axis 参数。 会广播值数组来配输入数组。' )
 
print ('沿轴 0 广播:') 
print (np.insert(a,1,[11],axis = 0) )
print ('\n'  )
 
print ('沿轴 1 广播:' )
print (np.insert(a,1,11,axis = 1))

# 输出结果
第一个数组:
[[1 2]
 [3 4]
 [5 6]]

未传递 Axis 参数。 在插入之前输入数组会被展开。
[ 1  2  3 11 12  4  5  6]


传递了 Axis 参数。 会广播值数组来配输入数组。
沿轴 0 广播:
[[ 1  2]
 [11 11]
 [ 3  4]
 [ 5  6]]


沿轴 1 广播:
[[ 1 11  2]
 [ 3 11  4]
 [ 5 11  6]]

numpy.delete

此函数返回从输入数组中删除指定子数组的新数组。 与insert()函数的情况一样,如果未提供轴参数,则输入数组将展开。 该函数接受以下参数:

Numpy.delete(arr, obj, axis)

其中:

  • arr:输入数组
  • obj:可以被切片,整数或者整数数组,表明要从输入数组删除的子数组
  • axis:沿着它删除给定子数组的轴,如果未提供,则输入数组会被展开

例子

import numpy as np 
a = np.arange(12).reshape(3,4) 
 
print '第一个数组:' 
print a 
print '\n'  
 
print '未传递 Axis 参数。 在插入之前输入数组会被展开。' 
print np.delete(a,5) 
print '\n'  
 
print '删除第二列:'  
print np.delete(a,1,axis = 1) 
print '\n'  
 
print '包含从数组中删除的替代值的切片:' 
a = np.array([1,2,3,4,5,6,7,8,9,10]) 
print np.delete(a, np.s_[::2])     # [::2] 表示 [start:end:step]

#输出如下:
第一个数组:
[[ 0 1 2 3]
 [ 4 5 6 7]
 [ 8 9 10 11]]
 
未传递 Axis 参数。 在插入之前输入数组会被展开。
[ 0 1 2 3 4 6 7 8 9 10 11]
 
删除第二列:
[[ 0 2 3]
 [ 4 6 7]
 [ 8 10 11]]
 
包含从数组中删除的替代值的切片:
[ 2 4 6 8 10]

numpy.unique

This function returns an array of deduplicated elements in the input array . The function can return a tuple containing the deduplicated array and the associated indexed array . The nature of the index depends on the type of the return parameter in the function call.
Notes: Remove duplicate elements , and return de-duplicated arrays will be sorted

numpy.unique(arr, return_index, return_inverse, return_counts)

in:

  • arr: input array, if it is not a one-dimensional array, it will be expanded
  • return_index: If true, returns the subscript of the element in the input array
  • return_inverse: If true, returns the subscript of the deduplicated array , which can be used to reconstruct the input array
  • return_counts: If true, returns the number of occurrences of elements in the deduplicated array in the original array

example

import numpy as np 
a = np.array([5,2,6,2,7,5,6,8,2,9]) 
 
print '第一个数组:' 
print a 
print '\n'  
 
print '第一个数组的去重值:' 
u = np.unique(a)      # 会排序
print u 
print '\n'  
 
print '去重数组的索引数组:' 
u,indices = np.unique(a, return_index = True) 
print indices 
print '\n'  
 
print '我们可以看到每个和原数组下标对应的数值:' 
print a 
print '\n'  
 
print '去重数组的下标:' 
u,indices = np.unique(a,return_inverse = True) 
print u 
print '\n' 
 
print '下标为:' 
print indices 
print '\n'  
 
print '使用下标重构原数组:' 
print u[indices] 
print '\n'  
 
print '返回去重元素的重复数量:' 
u,indices = np.unique(a,return_counts = True) 
print u 
print indices

输出如下:

 
第一个数组:
[5 2 6 2 7 5 6 8 2 9]
 
第一个数组的去重值:
[2 5 6 7 8 9]
 
去重数组的索引数组:
[1 0 2 4 7 9]
 
我们可以看到每个和原数组下标对应的数值:
[5 2 6 2 7 5 6 8 2 9]
 
去重数组的下标:
[2 5 6 7 8 9]
 
下标为:
[1 0 2 0 3 1 2 4 0 5]
 
使用下标重构原数组:
[5 2 6 2 7 5 6 8 2 9]
 
返回唯一元素的重复数量:
[2 5 6 7 8 9]
 [3 2 2 1 1 1]

Guess you like

Origin blog.csdn.net/wu_zhiyuan/article/details/126573248