天天看點

Numpy100道練習題+注解

Numpy是Python中一個用作資料分析的包,此處是GitHub中入門numpy的100道練習題。自己在動手時添加了一些注釋

# 1 導入numpy
from numpy.lib import stride_tricks
import pandas as pd
import scipy.spatial as quick
import os
from numpy.lib.function_base import meshgrid
from numpy.core.function_base import linspace
import numpy as np

# 列印numpy的版本及配置資訊
print(np.__version__)
print(np.show_config())

# 建立一個長度為10的空向量
Z = np.zeros(10)
print(Z)

# 找到任意資料的記憶體大小
Z = np.zeros((10, 10))
print("%d bytes" % (Z.size * Z.itemsize))

# 得到numpy的add說明文檔
np.info(np.add)

# 建立一個第五個值為0的1向量
Z = np.ones(10)
Z[4] = 0
print(Z)

# 建立值域範圍的數組
Z = np.arange(10, 30)
print(Z)

# 反轉數組
Z = Z[::-1]
print(Z)

# 查找非零元素位置索引
NZ = np.nonzero([1, 2, 0, 0, 1, 2])
print(NZ)

# 建立一個3x3的矩陣,值為0-8
Z = np.arange(0, 9).reshape(3, 3)
print(Z)

# 建立一個3x3的機關矩陣
Z = np.eye(3)
print(Z)

# 建立一個3x3x3的随機矩陣
Z = np.random.random((3, 3, 3))
print(Z)

# 建立10x10x10的數組
Z = np.random.random((10, 10))
#Z = [Z.min(),Z.max()];
# print(Z);
Zmin, Zmax = Z.min(), Z.max()
print(Zmin, Zmax)

# 建立長度為30的随機向量并找到它的平均值
Z = np.random.random(30)
Z_mean = Z.mean()
print(Z_mean)

# 建立一個二維數組,其中邊界值為1,其餘值為0
Z = np.ones((10, 10))
Z[1:-1, 1:-1] = 0
print(Z)

# 對于一個存在數組,如何對邊界添加0
Z = np.ones((5, 5))
Z = np.pad(Z, pad_width=1, mode='constant', constant_values=0)
print(Z)

# NaN = not a number, inf = infinity
# 表達式                #結果
0*np.nan  # nan
np.nan = np.nan  # False
np.inf > np.nan  # False
np.nan - np.nan  # nan
0.3 == 3*0.1  # False

# 建立一個5x5的數組,并設定1,2,3,4落在對角線下方
Z = np.diag(1 + np.arange(4), k=-1)
print(Z)

# 建立一個8x8的矩陣,并且設定為棋盤模式
Z = np.zeros((8, 8), dtype=int)
Z[1::2, ::2] = 1
Z[::2, 1::2] = 1
print(Z)

# 考慮一個(6,7,8)形狀的數組,其第100個元素的索引(x,y,z)是什麼
Z = np.unravel_index(100, (6, 7, 8))
print(Z)

# 用tile函數建立一個8x8的棋盤矩陣
Z = np.tile(np.array([[0, 1], [1, 0]]), (4, 4))
print(Z)

# 對于一個5x5的矩陣做歸一化:(x-min)/(max-min)
Z = np.random.random((5, 5))
Z_max, Z_min = Z.max(), Z.min()
Z = (Z - Z_min) / (Z_max - Z_min)
print(Z)


# 建立一個顔色描述為(RGBA)四個無符号字元的自定義dtype
color = np.dtype([("r", np.ubyte, 1),
                  ("g", np.ubyte, 1),
                  ("b", np.ubyte, 1),
                  ("a", np.ubyte, 1)])
print(color)

# 一個5x3的矩陣和一個3x2的矩陣相乘,實矩陣乘積是?
Z = np.dot(np.ones((5, 3)), np.ones((3, 2)))
print(Z)

# 給定一個數組,對其在3和8之間的所有元素取反
Z = np.arange(11)
Z[(3 < Z) & (Z <= 8)] *= -1
print(Z)

# 下面腳本運作結果
print(sum(range(5), -1))  # 9
print(sum(range(5), -1))  # 10

# 考慮一個整數向量Z,下清單達合法的是哪個
# Z**Z        #True
# 2<<Z>>2     #False
# Z < -Z      #True
# 1j*Z        #True   #複數
#
# Z/1/1       #True
# Z < Z >Z    #False

# 下面表達式的結果分别是多少?
# np.array(0)/np.array(0)  #NAN
# np.array(0) // np.array(0)  #0
# np.array([np.nan]).astype((int).astype(float) - 2.14748365e+09)

# 如何從零位開始棄入浮點數組?
Z = np.random.uniform(-10, +10, 10)
print(np.copysign(np.ceil(np.abs(Z)), Z))

# 如何找出兩個數組公共的元素?
Z1 = np.random.randint(0, 10, 10)
Z2 = np.random.randint(0, 10, 10)
print(np.intersect1d(Z1, Z2))

# 如何忽略所有的numpy警告
defaults = np.seterr(all="ignore")
Z = np.ones(1)

# Back to sanity
_ = np.seterr(**defaults)

# 另一個等價的方式,使用上下文管理器
# with np.errstate(divide = 'ignore')
#     Z = np.ones(1) / 0

# 下面的表達式是否為真
# np.sqrt(-1) == np.emath.sqrt(-1);       #False

# 如何獲得昨天,今天和明天的日期?
yesterday = np.datetime64('today', 'D') - np.timedelta64(1, 'D')
today = np.datetime64('today', 'D')
tomorrow = np.datetime64('today', 'D') + np.timedelta64(1, 'D')

# 怎麼獲得所有與2016年7月的所有日期
Z = np.arange('2016-07', '2016-08', dtype='datetime64[D]')
print(Z)

# 如何計算((A+B)*(-A、2))(不使用中間變量)
Z = np.arange('2016-07', '2016-08', dtype='datetime64[D]')
print(Z)

# 用5種不同的方法提取随機數組中的整數部分
Z = np.random.uniform(0, 10, 10)
print(Z-Z % 1)
print(np.floor(Z))
print(np.ceil(Z)-1)
print(Z.astype(int))
print(np.trunc(Z))

# 建立一個5x5的矩陣且每一行的值範圍為從0到4
Z = np.zeros((5, 5))
Z += np.arange(5)
print(Z)

# 如何用一個生成10個整數的函數來建構數組


def generate():
    for x in range(10):
        yield x


Z = np.fromiter(generate(), dtype=float, count=-1)
print(Z)

# 建立一個大小為10的向量,值域為0到1,不包括0和1
Z = np.linspace(0, 1, 12, endpoint=True)[1:-1]
print(Z)

# 建立一個大小為10的随機向量,并把它排序
Z = np.random.random(10)
Z.sort()
print(Z)

# 對一個小數組進行求和有沒有辦法比np.sum更快
Z = np.arange(10)
np.add.reduce(Z)
# np.add.reduce是numpy.add子產品中的一個ufunc(universal function)函數,c語言實作

# 如何判斷兩和随機數組相等
A = np.random.randint(0, 2, 5)
B = np.random.randint(0, 2, 5)
# 假設array的形狀(shape)相同和一個誤差容限
equal = np.allclose(A, B)
print(equal)

# 把數組變為隻讀
Z = np.zeros(5)
Z.flags.writeable = False
#Z[0] = 1;

# 将一個10x2的笛卡爾坐标矩陣轉換為極坐标
Z = np.random.random((10, 2))
X, Y = Z[:, 0], Z[:, 1]
R = np.sqrt(X**2 + Y**2)
T = np.arctan2(Y, X)
print(R)
print(T)

# 建立一個大小為10的随機向量并将
# 其中最大值替換為0
Z = np.random.random(10)
Z[Z.argmax()] = 0
print(Z)

# 建立一個結構化數組,其中x和y坐标覆寫[0,1]x[1,0]區域
Z = np.zeros((5, 5), [('x', float), ('y', float)])
Z['x'], Z['y'] = np.meshgrid(np.linspace(0, 1, 5), np.linspace(0, 1, 5))
print(Z)

# 給定兩個數組x和y,構造柯西矩陣
X = np.arange(8)
Y = X + 0.5
C = 1.0 / np.subtract.outer(X, Y)
print(C)
print(np.linalg.det(C))  # 計算行列式

# 列印每個類型的numppy的最大和最小可表示值
for dtype in [np.int8, np.int32, np.int64]:
    print(np.iinfo(dtype).min)
    print(np.iinfo(dtype).max)
for dtype in [np.float32, np.float64]:
    print(np.finfo(dtype).min)
    print(np.finfo(dtype).max)
    print(np.finfo(dtype).eps)

# 如何列印數組中所有值
# np.set_printoptions(threshold = np.nan);
Z = np.zeros((16, 16))
print(Z)

# 如何在數組中找出與給定标量接近的值
Z = np.arange(100)
V = np.random.uniform(0, 100)
index = (np.abs(Z-V)).argmin()
print(Z[index])


# //思考形狀如(100,2)的随機向量,求出點與點之間的距離
# //(提示:np.atleast_2d,T,np.sqrt)
z = np.random.random((100, 2))
X, Y = np.atleast_2d(z[:, 0], z[:, 1])
D = np.sqrt((X-X.T)**2+(Y-Y.T)**2)
print(D)

# 使用scipy庫更加快速
D = quick.distance.cdist(z, z)
print(D)

# 如何将一個32位float數組轉換為32位int數組
z = np.arange(10, dtype=np.int32)
z = z.astype(np.float32, copy=False)
print(z)

# 如何讀取下面的檔案(np.genfromtxt)
z = np.genfromtxt("example.txt", delimiter=",")
print(z)

# numpy數組枚舉(enumerate)的等價操作
# 提示:np.ndenumerate,np.ndindex
z = np.arange(9).reshape(3, 3)  # 單行數組變換為3x3數組
for index, value in np.ndenumerate(z):
    print(index, value)

for index in np.ndindex(z.shape):
    print(index, z[index])

# 建構一個二維高斯矩陣(np.meshgrid,np.exp)
X, Y = np.meshgrid(np.linspace(-1, 1, 10), np.linspace(-1, 1, 10))
D = np.sqrt(X**2+Y**2)
sigma, mu = 1.0, 0.0
G = np.exp(-((D-mu)**2/(2.0*sigma**2)))
print(G)

# 在二維數組的随機位置放置p個元素(np.put,np.random.choice)
n = 5
p = 3
z = np.zeros((n, n))
np.put(z, np.random.choice(range(n*n), p, replace=False), 1)
print(z)

# 減去矩陣每一行的平均值(mean(axis=,keepdims=))
x = np.random.rand(3, 4)
# 新
Y = x - x.mean(axis=1, keepdims=True)
# 舊
Y = x - x.mean(axis=1).reshape(-1, 1)
print(X, Y)

# 如何對數組第n列進行排序
z = np.random.randint(0, 10, (5, 3))
print(z)
print(z[z[:, 0].argsort()])

# 如何判斷一個給定的數組存在空列
z = np.random.randint(0, 3, (3, 10))
print((~z.any(axis=0)).any())

# 從數組找出與給定值最接近的值(np.abs,argmin,flat)
Z = np.random.uniform(0, 1, 10)
z = 0.5
m = Z[np.abs(Z-z).argmin()]
print(m)

# 形狀如(1,3)和形狀如(3,1)的兩個數組形狀,如何使用疊代器計算他們的和
A = np.arange(3).reshape(3, 1)
B = np.arange(3).reshape(1, 3)
it = np.nditer([A, B, None])
for x, y, z in it:
    z[...] = x+y
print(it.operands[2])

# 建立一個具有name屬性的數組類


class NamedArray (np.ndarray):
    def __new__(cls, array, name="no name"):
        obj = np.asarray(array).view(cls)
        obj.name = name
        return obj

    def __array_finalize__(self, obj):
        if obj is None:
            return
        self.info = getattr(obj, 'name', "no name")


Z_name = NamedArray(np.ones(10), "range_10")
print(Z_name.name)

# 給定一個向量,如何讓在第二個向索引的每個元素加1(注意重複索引)(提示:np.biincount | np.add.at)
Z = np.ones(10)
I = np.random.randint(0, len(Z), 20)
Z += np.bincount(I, minlength=len(Z))
print(Z)

np.add.at(Z, I, 1)
print(Z)

# 如何根據索引清單I将向量X的元素累加到數組F中(提示:np.bincount)
X = [1, 3, 3, 3, 4, 1]
I = [1, 3, 3, 3, 4, 1]
F = np.bincount(I, X)  # 數組I長度中各個資料重複值,将重複值帶入X(類似各個資料節點對應權值)中相加為結果
print(F)

# 思考(dtype=ubyte)的(w,h,3)圖像,計算唯一顔色的數量
w, h = 16, 16
I = np.random.randint(0, 3, (h, w, 3)).astype(np.ubyte)
F = I[..., 0]*256*256 + I[..., 1]*256 + I[..., 2]
n = len(np.unique(F))
print(n)

# 考慮一個四維數組如何一次計算最後兩個軸(axis)的和(提示:sum(axis=(-2,-1)))
A = np.random.randint(0, 10, (3, 4, 3, 4))
sum = A.sum(axis=(-2, -1))
print(sum)
# 方法二
sum = A.reshape(A.shape[:-2]+(-1,)).sum(axis=-1)
print(sum)

# 給定一個一維向量D,如何使用相同大小的向量S來計算D子集的均值(提示:np.bincount)
D = np.random.uniform(0, 1, 100)
S = np.random.randint(0, 10, 100)
D_sums = np.bincount(S, weights=D)
D_counts = np.bincount(S)
D_means = D_sums/D_counts
print(D_means)
# 方法二
print(pd.Series(D).groupby(S).mean())

# 如何獲得點積dot product的對角線(提示:np.diag)
A = np.random.uniform(0, 1, (5, 5))
B = np.random.uniform(0, 1, (5, 5))
# slow version
w = np.diag(np.dot(A, B))
# 方法2
# Fast version
np.sum(A*B.T, axis=1)
# 方法3
# Faster version
np.einsum("ij,ji->i", A, B)

# 考慮一個向量【1,2,3,4,5】,如何建立一個新的向量,在這個新的向量中每個值之間有3個連續的零(array[::4])
z = np.array([1, 2, 3, 4, 5])  # np.arange(1,6)
nz = 3
z0 = np.zeros(len(z)+(len(z)-1)*(nz))
z0[::nz+1] = z  # 間隔4插入z
print(z0)

# 考慮一個 (5,5,3)的數組,如何将其與一個(5,5)數組相乘(提示:array[:,:,None])
A = np.random.randint(1, 4, (5, 5, 3))
B = 2*np.ones((5, 5))
print(A*B[:, :, None])

# 如何對一個數組中任意兩行做交換(array[[]] = array[[]])
A = np.arange(25).reshape(5, 5)
A[[0, 1]] = A[[1, 0]]
print(A)

# 考慮一個可以描述10個三角形的triplets,找到可以分割全部三角形的line segment(提示:repeat,np.roll,np.sort,view,np.unique)
faces = np.random.randint(0, 100, (10, 3))
"""
numpy.roll(a,shift,axis=None)沿着給定軸滾動數組元素。超出最後位置的元素将會復原到第一個位置
将a沿着axis方向滾動shift長度 a:輸入數組 shift:滾動長度(若為元組則軸也為元組) 
axis:滾動軸 0為垂直滾動,1為水準滾動(若為None則數組在移位前扁平化,之後恢複原狀)
輸出與a次元一緻

numpy.repaet(a,num,axis=None)沿着給定軸複制數組元素num次,會增加原數組次元
axis=None:扁平化,每個元素複制num次
axis=0:沿着列方向複制,每行元素複制num次
axis=1:沿着行方向複制,每列元素複制num次

numpy.ndarray.view函數對記憶體區域不同的切割方式,來完成資料類型的轉換,無需對資料進行額外的copy
但記憶體需要連續

a,b,c = numpy.unique(A,return_index=True,return_inverse=True)函數取出原數組中重複元素,并按照元素由大到小傳回新元組或清單
a:無重複元素的新數組
b:新數組元素在原數組中位置
c:舊數組元素在新數組中位置
"""

F = np.roll(faces.repeat(2, axis=1), -1, axis=1)
F = F.reshape(len(F)*3, 2)
"""
np.sort函數:按照行進行排序
axis=0:按照列進行排序
axis=1:按照行進行排序
預設按照行進行排序
"""
F = np.sort(F, axis=1)
"""
view函數用法
"""
G = F.view(dtype=[('p0', F.dtype), ('p1', F.dtype)])
D = np.unique(G)
print(G)

# 給定一個二進制的數組C,如何産生一個數組A滿足np.bincount(A)==C
C = np.bincount([1, 1, 2, 3, 4, 4, 6])
A = np.repeat(np.arange(len(C)), C)
print(A)

# 如何通過滑動視窗計算一個數組的平均數(提示:np.cumsum)
"""
np.cumsum 數組累加
"""


def moving_average(a, n=3):
    ret = np.cumsum(a, dtype=float)
    ret[n:] = ret[n:]-ret[:-n]
    return ret[n - 1:]/n


Z = np.arange(20)
print(moving_average(Z, n=3))

# 思考一維數組Z,建構一個二維數組,其第一行是(Z[0],Z[1],Z[2]),然後每一行移動一位,最後一行為(Z[-3],Z[-2],Z[-1])提示:from numpy.lib import stride_tricks
"""
stride_tricks.as_strided(x,shape=None,strides=None,subok=False,writeable=True)

np.itemsize()數組中每個元素位元組長度
"""


def rolling(a, window):
    shape = (a.size - window + 1, window)
    strides = (a.itemsize, a.itemsize)
    return stride_tricks.as_strided(a, shape=shape, strides=strides)


Z = rolling(np.arange(10, dtype=np.int8), 3)
print(Z)

# 如何對bool值取反,或者原位(in-place)改變浮點數的符号(sign)提示:np.logical_not,np.negative
Z = np.random.randint(0, 2, 100)
np.logical_not(Z, out=Z)

Z = np.random.uniform(-1.1, 1.0, 100)
np.negative(Z, out=Z)

# 考慮兩組點集P0和P1去描述一組棧(二維)和一個點p,如何計算點p到每一條線i(P0[i],P1[i])的垂直距離
"""
numpy.sum(a,axis=None,,dtype=None,out=None,keepdim=np._NoValue)函數中
a:用于計算加法性質的數組
axis:None表示所有元素直接相加;0:每列元素相加 1:每行元素相加
axis為整數元組(x,y),則是求axis=x和axis=y情況下得到的和值
keepdim=True:確定矩陣在進行行列壓縮運算之後矩陣次元保持不變
"""


def distance(P0, P1, p):
    T = P1 - P0
    L = (T**2).sum(axis=1)
    U = -((P0[:, 0]-p[..., 0])*T[:, 0]+(P0[:, 1]-P[..., 1])*T[:, 1])/L
    U = U.reshape(len(U), 1)
    D = P0 + U*T - P
    return np.sqrt((D**2).sum(axis=1))


P0 = np.random.uniform(-10, 10, (10, 2))
P1 = np.random.uniform(-10, 10, (10, 2))
P = np.random.uniform(-10, 10, (1, 2))  # 一個點
print(distance(P0, P1, P))

# 點集p到P0與P1連線的距離
P = np.random.uniform(-10, 10, (10, 2))
print(np.array([distance(P0, P1, P) for P_i in P]))

# 思考一個任意維數組,編寫一個函數,該函數提取一個具有固定形狀的子部分,并以給定元素為中心(在該部分填充)
# 提示:minimum,maximum
"""
numpy.max:(a,axis=None,out=None,keepdims=False)預設為列向取值
numpy.maximum:(X,Y,out=None)~X,Y逐位進行比較,取較大者,最少接收兩個參數(Y可為單一進制素)
numpy.minimum:
slice:(start,end)~可以提取字元串的某個部分,并以新的字元串傳回被提取的部分
zip:([iterable,...]) iterable為可疊代的對象,并且可以有多個參數。該函數傳回一個以元組為元素的清單,
其中第i個元組包含每個參數序列的第i個元素。傳回的清單長度被截斷為最短的參數序列長度。隻有一個序列參數時,
它傳回一個一進制組的清單,沒有參數時,傳回空清單

"""
Z = np.random.randint(0, 10, (10, 10))
shape = (5, 5)
fill = 0
position = (1, 1)
R = np.ones(shape, dtype=Z.dtype)*fill
P = np.array(list(position)).astype(int)
Rs = np.array(list(R.shape)).astype(int)
Zs = np.array(list(Z.shape)).astype(int)

R_start = np.zeros((len(shape),)).astype(int)
R_stop = np.array(list(shape)).astype(int)
Z_start = (P-Rs//2)
Z_stop = (P+Rs//2)+Rs % 2

R_start = (R_start - np.minimum(Z_start, 0)).tolist()
Z_start = (np.maximum(Z_start, 0)).tolist()
R_stop = np.maximum(R_start, (R_stop-np.maximum(Z_stop-Zs, 0))).tolist()
Z_stop = (np.minimum(Z_stop, Zs)).tolist()

r = [slice(start, stop) for start, stop in zip(R_start, R_stop)]
z = [slice(start, stop) for start, stop in zip(Z_start, Z_stop)]
R[r] = Z[z]
print(Z)
print(R)

# 考慮一個數組Z=[1,2,3,4,5,6,7,8,9,10,11,12,13,14],如何生成一個
# 數組R=[[1,2,3,4],[2,3,4,5],[3.4.5.6],..,[11,12,13,14]] 提示:stride_tricks.as_strided()
"""
stride_tricks.as_strided(a,shape=None,strides=None) 移動步長按照位元組進行計算
"""
Z = np.arange(1, 15, dtype=np.uint32)
R = stride_tricks.as_strided(Z, (11, 4), (4, 4))
print(R)

# 計算一個矩陣的秩 提示:np.linalg.svd
"""
U,S,V=numpy.linalg.svd(a,full_matrices=1,compute_uv=1
參數:
a是一個形如(M,N)矩陣
full_matrices的取值是為0或者1,預設值為1,這時u的大小為(M,M),v的大小為(N,N)。
否則u的大小為(M,K),v的大小為(K,N) K=min(M,N)
compute_uv的取值是為0或者1,預設值為1,表示計算u,s,v。為0的時候隻計算s
a = U*S*V
S為奇異值分解,對角元素為奇異值,按從大到小排列,其他元素均為0.
"""
Z = np.random.uniform(0, 1, (10, 10))
U, S, V = np.linalg.svd(Z)
rank = np.sum(S > 1e-10)
print(rank)

# 如何找到一個數組中頻率最高的值
Z = np.random.randint(0, 10, 50)
print(np.bincount(Z).argmax())

# 從一個10x10的矩陣中提取出連續的3x3的區塊 提示:stride_tricks.as_strided
Z = np.random.randint(0, 5, (10, 10), dtype=np.uint32)
n = 3
i = 1 + (Z.shape[0]-3)
j = 1 + (Z.shape[1]-3)
C = stride_tricks.as_strided(
    Z, shape=(i, j, n, n), strides=Z.strides+Z.strides)
print(C)

# 建立一個Z[i,j] = Z[i,j]的子類 提示:class方法
"""

"""


class Symetric(np.ndarray):
    def __setitem__(self, index, value):
        i, j = index
        super(Symetric, self).__setitem__((i, j), value)
        super(Symetric, self).__setitem__((j, i), value)


def symetric(Z):
    return np.asarray(Z+Z.T-np.diag(Z.diagonal())) .view(Symetric)


S = symetric(np.random.randint(0, 10, (5, 5)))

print(S)

# 對于一個16x16的數組,如何得到一個區域(block-sum)的和(區域大小為4x4)提示:np.add.reduceat
"""
np.add.reduceat:通過清單indices參數(清單形式)指定一系列插入reduce的起始和終止位置(reduce at).
規則:如果indice中某元素小于其後面元素,則相應結果為這兩個元素位置産生的slice裡的數組元素。對于最後一個元素
因為其後再無其他元素,結果為對所有元素進行reduce
"""
Z = np.ones((16, 16))
K = 4
S = np.add.reduceat(np.add.reduceat(Z, np.arange(0, Z.shape[0], K), axis=0),
                    np.arange(0, Z.shape[1], K), axis=1)
print(S)

# 如何利用numpy實作Game of life 提示:game of life


def iterate(Z):
    # Count number
    N = (Z[0:-2, 0:-2]+Z[0:-2, 1:-1]+Z[0:-2, 2:] +
         Z[1:-1, 0:-2] + Z[1:-1, 2:] +
         Z[2:, 0:-2]+Z[2:, 1:-1]+Z[2:, 2:])
    # Apply rule
    birth = (N == 3) & (Z[1:-1, 1:-1] == 0)
    survive = ((N == 2) | (N == 3)) & (Z[1:-1, 1:-1] == 1)
    Z[...] = 0
    Z[1:-1, 1:-1][birth | survive] = 1
    return Z


Z = np.random.randint(0, 2, (50, 50))
for i in range(100):
    Z = iterate(Z)
print(Z)

# 如何找到一個數組的第n個最大值 提示:np.argsort|np.argpartition
"""
numpy.shuffle:對數組進行随機排序
numpy.argsort:對資料進行排序
np.argpartition:排序數組,在前面的小于該索引處值,後面大于
"""
Z = np.arange(10000)
np.random.shuffle(Z)
n = 5
# slow
print(Z[np.argsort(Z)[-n:]])
# Fast
print(Z[np.argpartition(-Z, n)[:n]])

# 給定任意個數向量,建立笛卡爾積(每一個元素的每一種組合)
"""
numpy.indices:數組切片
enumerate:枚舉對象,索引加資料值
"""


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


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

# 如何從一個正常數組建立記錄數組(record array) 提示:np.core.records.fromarrays
"""
np.core.records.fromarrays(arrayList,dtype=None,shape=None,formats=None,names=None,title=None,aligned=False,byteorder=none)[source]:
arrayList:list或tuple類數組對象的清單(例如:清單,元組和ndarray)
dtype:data-type,可選所有數組的有效dtype
shape:int或ints的tuple,可選所得數組的Shape。如果未提供,則從arrayList[0]推斷
formates,names,titles,aligned,byteorder:如果dtype為None,則從這些參數傳遞給numpy,format_parser以建構dtype
傳回值:np.recarry記錄由給定的arrayList列組成的數組
"""
Z = np.array([("Hello", 2.5, 3),
              ("World", 3.6, 2)])
R = np.core.records.fromarrays(Z.T,
                               names='col1,col2,col3',
                               formats='S8,f8,i8')
print(R)

# 考慮一個大向量,考慮如何用三種不同方式計算它的立方 提示:np.power,*,np.einsum
x = np.random.rand()
np.power(x, 3)
# 方式2
x*x*x
# 方式3
np.einsum('i,i,i->i', x, x, x)

# 考慮兩個形狀分别為(8,3)和(2,2)的數組A,B,如何在數組A中找到滿足包含B中元素的行(不包含B中每行元素順序)提示:np.where
"""
np.where(condition,x,y):滿足條件(condition),輸出x,不滿足輸出y
np.where(condition):隻有條件(condition),沒有x和y。則輸出滿足條件(即:非0)元素的坐标,這裡坐标以tuple的形式輸出,通常原數組幾維,
輸出的tuple中包含幾個數組,分别對應符合條件元素的各維坐标
np.newaxis:增加矩陣次元
"""
A = np.random.randint(0, 5, (8, 3))
B = np.random.randint(0, 5, (2, 2))
C = (A[..., np.newaxis, np.newaxis] == B)
rows = np.where(C.any((3, 1)).all(1))[0]
print(rows)

# 考慮一個10x3的矩陣,分解出有不完全相同值的行
Z = np.random.randint(0, 5, (10, 3))
print(Z)
# solution for array of all dtype(including string arrays and record arra)
E = np.all(Z[:, 1:] == Z[:, :-1], axis=1)
U = Z[~E]
print(U)
# 方法二
# solution for numerical arrays only, will work for any number of columns in
U = Z[Z.max(axis=1) != Z.min(axis=1), :]
print(U)

# 将一個整數向量轉換為matrix binary的表現形式 提示:np.unpackbits
"""
np.unpackbits:整數轉換為2進制
"""
I = np.array([0, 1, 2, 3, 15, 16, 32, 64, 128], dtype=np.uint8)
B = ((I.reshape(-1, 1) & (2*np.arange(8))) != 0).astype(int)
print(B[:, ::-1])
# 方法二
# print(np.unpackbits(I[:,np.newaxis],axis=1))
print(np.unpackbits(I.reshape(-1, 1), axis=0))

# 給定一個二維數組,如何提取出唯一的(unique)行  提示:np.ascontiguousarray
"""
np.ascontiguousarray():将記憶體不連續數組轉換為記憶體連續數組
"""
Z = np.random.randint(0, 2, (6, 3))
T = np.ascontiguousarray(Z).view(
    np.dtype((np.void, Z.dtype.itemsize*Z.shape[1])))
_, idx = np.unique(T, return_index=True)
uZ = Z[idx]
print(uZ)

# 考慮兩個向量A和B,寫出用einsum等式對應的inner,outer,sum,mul函數 提示:np.einsum
"""
np.einsum函數:愛因斯坦求和約定操作指定在numpy中的運算

"""
# A和B是兩個形狀相容的一維數組(相應的軸的長度要麼相等,要麼其中一個長度為1)
A = np.random.randint(1, 2, 10)
B = np.random.randint(1, 2, 10)
print("傳回數組A的視圖")
print(np.einsum('i', A))  # A
print('數組A的總和')
print(np.einsum('i->', A))  # np.sum(A)
print('A和B的數組元素依次相乘')
print(np.einsum('i,i->i', A, B))  # A*B
print('A和B的點積(内積)inner')
print(np.einsum('i,i', A, B))  # np.inner(A,B)
print('A和B的外積(叉積)outer')
print(np.einsum('i,j->ij', A, B))  # np.outer(A,B)

# A和B為與之相容的兩個二維數組
A = np.random.randint(1, 2, 16).reshape(4, 4)
B = np.random.randint(1, 2, 16).reshape(4, 4)
print("傳回A的視圖")
print(np.einsum('ij', A))  # A
print("A的轉置")
print(np.einsum('ji', A))  # A.T
print("A的主對角線")
print(np.einsum('ii->i', A))  # np.diag(A)
print("A的主對角線的和")
print(np.einsum('ii', A))  # np.trace(A)
print("A的值相加")
print(np.einsum('ij->', A))  # np.sum(A)
print("A的軸垂直(列)求和")
print(np.einsum('ij->j', A))  # np.sum(A,axis=0)
print("A的軸水準(行)求和")
print(np.einsum('ij->i', A))  # np.sum(A,axis=1)
print("A和B逐個元素依次相乘")
print(np.einsum('ij,ij->ij', A, B))  # A*B
print("A和B的轉置逐個元素依次相乘")
print(np.einsum('ij,ji->ij', A, B))  # A*B.T
print("A和B的矩陣乘法")
print(np.einsum('ij,jk->ik', A, B))  # dot(A,B)
print("A和B的内積")
print(np.einsum('ij,kj->ik', A, B))  # inner(A,B)
print("A的每一行乘以B")
print(np.einsum('ij,kj->ikj', A, B))  # A[:,None]*B
print("A的每個值乘以B")
print(np.einsum('ij,kl->ijkl', A, B))  # A[:,:,None,None]*B

# 考慮一個由兩個向量描述的路徑(X,Y),如何用等距樣例對其進行采樣 提示:np.comsum np.interp
"""
np.comsum(a,axis):按照axis累加,不指定axis,則壓縮為一維
np.interp(a,x,y):在a序列中插入橫坐标x,縱坐标y的點
"""
phi = np.arange(0, 10*np.pi, 0.1)
a = 1
x = a*phi*np.cos(phi)
y = a*phi*np.sin(phi)
dr = (np.diff(x)**2 + np.diff(y)**2)**(1//2)  # 長度
r = np.zeros_like(x)
r[1:] = np.cumsum(dr)
r_int = np.linspace(0, r.max(), 200)
x_int = np.interp(r_int, r, x)        #
y_int = np.interp(r_int, r, y)

# 給定一個整數n和一個二維數組X,從X中選擇可以被解釋為從多n度的多項分布式的行,即這些行隻包含整數對n的和 提示:np.logical_and.reduce,np.mod
"""
np.logical_and.reduce:邏輯運算符号
np.mod(a,b):相當于a%b,符号與b相同
"""
X = np.asarray([[1.0, 0.0, 3.0, 8.0],
                [2.0, 0.0, 1.0, 1.0],
                [1.5, 2.5, 1.0, 0.0]])
n = 4
M = np.logical_and.reduce(np.mod(X, 1) == 0, axis=-1)
M &= (X.sum(axis=-1) == n)  # -1表示倒數第一個(即最後一個次元)
print(X[M])

# 對于一個一維數組X,計算它boostrapped之後的95%置信區間的平均值 提示:np.percentile
"""
np.percentile:百分比分位數計算
"""
X = np.random.randn(100)  # 随機産生一個一維的array數組
N = 1000  # 樣例
idx = np.random.randint(0, X.size, (N, X.size))
mean = X[idx].mean(axis=1)
confint = np.percentile(mean, [2.5, 97.5])
print(confint)