《NumPy Beginner's Guide》笔记Chapter5

时间:2023-02-09 14:29:28
# -*- coding: utf-8 -*-
from __future__ import division
__author__ = 'ZengDong'
#日期 = 22:13

""" Chapter5: Working with Matrices and ufuncs """
import numpy as np
""" 1. Matrices Matrices in NumPy are subclasses of ndarray. We can create matrices with the mat, matrix, and bmat functions function: np.mat A.T 转置 A.I 求逆 """
#Matrices can be created with the mat function
#Rows are delimited by a semicolon, values by a space 分号分行,空格分值
A = np.mat("1 2 3; 4 9 6; 7 8 19");
print("Create from string", A)
""" 输出: ('Create from string', matrix([[1, 2, 3], [4, 9, 6], [7, 8, 19]])) """
#transpose the matrix with the T function
print("transpose A", A.T)  #输出A的转置

#the matrix can be inverted with the I attribute
print("Inverse A", A.I)
print("Mat multi", A.I * A)   #1 ... 1 ... 1


#instead of using a string to create a matrix ,let's do it with an array
print("Create from array", np.mat(np.arange(9).reshape(3, 3)))
""" 输出: ('Create from array', matrix([[0, 1, 2], [3, 4, 5], [6, 7, 8]])) """


""" 2. Creating a matrix from other matrices Sometimes we want to create a matrix from other smaller matrices. We can do this with the bmat function. The b here stands for block matrix. function: bmat """
#create a two-by-two identify matrix
A = np.eye(2)
print("A", A)

B= 2 * A
print("B", B)

#create the compound matrix from a string.
print("Compound matrix\n", np.bmat("A B; A B"))
""" 输出: ('Compound matrix\n', matrix([[ 1., 0., 2., 0.], [ 0., 1., 0., 2.], [ 1., 0., 2., 0.], [ 0., 1., 0., 2.]])) """


""" 3. Universal functions Ufuncs expect a set of scalars as input and produce a set of scalars as output function: frompyfunc """

#define a Python function that answer the ultimate question to the universe.
def ultimate_answer(a):
    result = np.zeros_like(a)
    result.flat = 42
# result.fill(42) #faster
    return result


#create a universal function with frompyfunc;
#specify 1 as as number of input parameter followed by 1 as the number of output parameters:

ufunc = np.frompyfunc(ultimate_answer, 1, 1)
print("The answer", ufunc(np.arange(4)))   #输出 ('The answer', array([array(42), array(42), array(42), array(42)], dtype=object))

#we can do the same for a two-dimensional array by using the follwing code:
print("The answer", ufunc(np.arange(4).reshape(2, 2)))
""" 输出: ('The answer', array([[array(42), array(42)], [array(42), array(42)]], dtype=object)) """






""" 4. Universal functions How can functions have methods? As we said earlier, universal functions are not functions but objects representing functions. Universal functions have four methods. function: reduce accumulate reduceat outer add """
#The input array is reduced by applying the universal function recursively along a specified axis on consecutive elements.
a = np.arange(9)
print("Add Reduce", np.add.reduce(a))   #输出36

#The accumulate method also recursively goes through the input array
#But, contrary to the reduce method, it stores the intermediate results in an array and returns that.
print("Accumulate", np.add.accumulate(a))  #输出('Accumulate', array([ 0, 1, 3, 6, 10, 15, 21, 28, 36]))



#The reduceat method is a bit complicated to explain.
print("Reduceat", np.add.reduceat(a, [0, 5, 2, 7]))
""" 输出: ('Reduceat', array([10, 5, 20, 15])) 1. The first step concerns the indices 0 and 5. This step results in a reduce operation of the array elements between indices 0 and 5. 2.The second step concerns indices 5 and 2. Since 2 is less than 5, the array element at index 5 is returned: 3. The third step concerns indices 2 and 7. This step results in a reduce operation of the array elements between indices 2 and 7: 4. The fourth step concerns index 7. This step results in a reduce operation of the array elements from index 7 to the end of the array: """


#the outer method returns an array that has a rank

print("Outer", np.add.outer(np.arange(3), a))
""" 输出;('Outer', array([[ 0, 1, 2, 3, 4, 5, 6, 7, 8], [ 1, 2, 3, 4, 5, 6, 7, 8, 9], [ 2, 3, 4, 5, 6, 7, 8, 9, 10]])) """






""" 5. Arithmetic functions The common arithmetic operators +, -, and * are implicitly linked to the add, subtract, and multiply universal functions. There are three universal functions that have to do with array division: divide, true_divide, and floor_division. Two operators correspond to division: / and //. function: divide true_divide floor_divide / // """

#The divide function does truncate integer division and normal floating-point division 取整
a = np.array([2, 6, 5])
b = np.array([1, 2, 3])
print("Divide", np.divide(a, b), np.divide(b, a))  #输出('Divide', array([2, 3, 1]), array([0, 0, 0]))


#The true_divide function comes closer to the mathematical definition of division.
#Integer division returns a floating-point result and no truncation occurs:
print("True Divide", np.true_divide(a, b), np.true_divide(b, a))
#输出:('True Divide', array([ 2. , 3. , 1.66666667]), array([ 0.5 , 0.33333333, 0.6 ]))


#The floor_divide function always returns an integer result. It is equivalent to
#calling the floor function after calling the divide function.

print("Floor Divide", np.floor_divide(a, b), np.floor_divide(b, a))
#输出:('Floor Divide', array([2, 3, 1]), array([0, 0, 0]))

c = 3.14 * b
print("Floor Divide 2", np.floor_divide(c, b), np.floor_divide(b, c))
#输出:('Floor Divide 2', array([ 3., 3., 3.]), array([ 0., 0., 0.]))


#By default, the / operator is equivalent to calling the divide function:
#from __future__ import division
#if the upper line is found at the begining of a Python program, the true_divide function is called
print("/ operator", a/b, b/a)  #输出:('/ operator', array([ 2. , 3. , 1.66666667]), array([ 0.5 , 0.33333333, 0.6 ]))


#the // operator is equivalent to calling the floor_divide function
print("// operator", a//b, b//a)
print("// operator 2", c//b, b//c)








""" 6. Modulo operation The modulo or remainder can be calculated using the NumPy mod, remainder, and fmod functions.Also, one can use the % operator. The main difference among these functions is how they deal with negative numbers function: mod remainder fmod % """

#the remainder function returns the remainder of the two arrays, element-wise.
a = np.arange(-4, 4)
print("Remainder", np.remainder(a, 2))   #输出('Remainder', array([0, 1, 0, 1, 0, 1, 0, 1]))

#the mod function does exactly the same as the remainder function
print("Mod", np.mod(a, 2))   #输出:('Mod', array([0, 1, 0, 1, 0, 1, 0, 1]))

#the % operator is just shorthand for the remainder function
print("% operator", a % 2)    #输出:('% operator', array([0, 1, 0, 1, 0, 1, 0, 1]))


#the fmod function handles negative numbers differently than mod, fmod, and % do.
#The sign of the remainder is the sign of the dividend, and the sign of the divisor has no influence on the result
print("Fmod", np.fmod(a, 2))   #输出:('Fmod', array([ 0, -1, 0, -1, 0, 1, 0, 1]))




""" 6.Fibonacci numbers The Fibonacci numbers are based on a recurrence relation. function: matrix rint: The rint function rounds numbers to the closest integer, but the result is not integer. """
#create the Fibonacci matrix as follows:
F= np.matrix([[1, 1], [1, 0]])
print("F", F)

#calculate the eight Fibonacci number
""" (1, 1) (x1 (x2 (1, 0) x0) 相乘就得到 x1) 同理依次迭代..... """
print("8th Fibonacci", (F ** 7)[0, 0])   #输出:('8th Fibonacci', 21)


#The golden ratio formula, better known as Binet's formula, allows us to calculate
#Fibonacci numbers with a rounding step at the end. Calculate the first eight Fibonacci numbers:
n = np.arange(1, 9)
sqrt5 = np.sqrt(5)
phi = (1 + sqrt5) / 2
fibonacci = np.rint((phi**n - (-1/phi)**n)/sqrt5)
print("Fibonacci", fibonacci)   #输出:('Fibonacci', array([ 1., 1., 2., 3., 5., 8., 13., 21.]))





""" 7.Lissajous curves All the standard trigonometric functions, such as, sin, cos, tan and likewise are represented by universal functions in NumPy function: """
#Initialize t with the linspace function from -pi to pi with 201 points:
a = float(9)
b = float(8)
t = np.linspace(-np.pi, np.pi, 201)

#calculate x with the sin function an np.pi
x = np.sin(a * t + np.pi / 2)

#calculate y with the sin function
y = np.sin(b * t)

import matplotlib.pyplot as plt
plt.plot(x, y)
#plt.show()






""" 7.Square waves Square waves are also one of those neat things that you can view on an oscilloscope. They can be approximated pretty well with sine waves; after all, a square wave is a signal that can be represented by an infinite Fourier series. function: """
#initializing t and k
t = np.linspace(-np.pi, np.pi, 201)
k = np.arange(1, float(2000))
k = 2 * k -1
f = np.zeros_like(t)


""" 方法1: """
import time
tic = time.time()
for count in range(100):
    for i in range(len(t)):
        f[i] = np.sum(np.sin(k * t[i]) / k)
    f = (4 / np.pi) * f
toc = time.time()
print("time1 = %f s" % (toc - tic))

#问题1:
#You may have noticed that there is one loop in the code. Get rid of it with NumPy functions
#and make sure the performance is also improved.
""" 方法2: 去除循环 t = t.reshape(len(t), 1) k = k.reshape(1, len(k)) f = np.sum( np.sin(np.dot(t, k)) / k ,axis = 1) """
t = t.reshape(len(t), 1)
k = k.reshape(1, len(k))

tic = time.time()
for count in range(100):
    f = np.sum( np.sin(np.dot(t, k))  / k   ,axis = 1)
toc = time.time()
print("time2 = %f s" % (toc - tic))

""" 妈蛋: time1 = 1.214000 s time2 = 1.417000 s time2 > time1 估计不是这么写...以后再改吧【未解决】 """



plt.clf()
plt.plot(t, f)
#plt.show()







""" 8.Sawtooth and triangle waves Sawtooth and triangle waves are also a phenomenon easily viewed on an oscilloscope. Just like with square waves, we can define an infinite Fourier series. function: """
t = np.linspace(-np.pi, np.pi, 201)
k = np.arange(1, 1000)
f = np.zeros_like(t)


for i in range(len(t)):
    f[i] = np.sum(np.sin(2 * np.pi * k * t[i]) / k)
f = (-2 / np.pi) * f


plt.clf()
plt.plot(t, f)
#plt.show()




""" 9.Bitwise and comparison functions Bitwise functions operate on the bits of integers or integer arrays, since they are universal functions. The operators ^, &, |, <<, >>, and so on, have their NumPy counterparts. function: """
#The first trick depends on the XOR or ^ operator. The XOR operator is also called
#the inequality operator; so, if the sign bit of the two operands is different, the XOR
#operation will lead to a negative number. ^ corresponds to the bitwise_xor
#function. < corresponds to the less function.
x = np.arange(-9, 9)
y = -x
print("Sign different?", (x^y) < 0)
print("Sign different?", np.less(np.bitwise_xor(x, y), 0))






#A power of two is represented by a 1, followed by a series of trailing zeroes in binary
#notation. For instance, 10, 100, or 1000. A number one less than a power of two
#would be represented by a row of ones in binary. For instance, 11, 111, or 1111
#(or 3, 7, and 15, in the decimal system). Now, if we bitwise the AND operator a power
#of two, and the integer that is one less than that, then we should get 0. The NumPy
#counterpart of & is bitwise_and; the counterpart of == is the equal universal function.

#10000 小于1就是
#01111 AND运算 0
print("Power of 2?\n", x, "\n", (x & (x -1)) == 0)
print("Power of 2?\n", x, "\n", np.equal(np.bitwise_and(x, (x - 1)), 0))






print("Modulus 4\n", x, "\n", x & ((1 << 2) - 1))
print("Modulus 4\n", x, "\n", np.bitwise_and(x, np.left_shift(1, 2) - 1))