Pandas 数据分析基础

import pandas as pd
pandas序列(Series)
data = pd.Series([0.1, 0.2, 0.3, 1.0]) #自动维护标号索引,支持下标切片
data = pd.Series([1,2,3,4], index=['a', 'b', 'c', 'd']) #指定索引
data.iloc[1] #按位置索引
#迭代器
for i in data.values:
print(i)
# 使用词典初始化序列
sdata = {'a':1, 'b':2, 'c':3}
keys = ['b', 'c', 'd']
obj = pd.Series(sdata, index = keys) # 'd'为Nan, 'a'被删去


pandas二维数据表(DataFrame)

多序列合并生成dataframe

dict1 = {'a':1, 'b': 2, 'c':3}
sdata_1 = pd.Series(dict1)
dict2 = {'a':2020, 'b':2021, 'c':2022}
sdata_2 = pd.Series(dict2)
df = pd.DataFrame({'c1': sdata_1, 'c2': sdata_2})
# 非对齐情况:用NaN填充


用二维Numpy数组生成:

pd.DataFrame(np.random.rand(3,2),
columns=['foo', 'bar'], index=['a', 'b', 'c'])

其他可以输入给DataFrame构造器的数据:
二维ndarray, 由数组、列表或元组组成的字典(每个序列变成DataFrame的一列, 长度必须相同),由Series组成的字典等

索引

state.index # 行索引 Index ['a', 'b', 'c']
state.columns # 列索引 Index ['c1', 'c2']


Pandas Index Object 与 表间关联计算
集合运算

indA = pd.Index([1,2,3,4,5])
indB = pd.Index([2,4,6,8])
indA & ind B
# Ind64Index([2,4])
ind A | ind B
# Ind64Index([1,2,3,4,5,6,8])
indA ^ indB
# Ind64Index([1,3,5,8])


索引

df = pd.DataFrame({'c1': sdata_1, 'c2': sdata_2})
df['c1'] #按列索引
df.c1 #也可使用字段名作为属性
df['c3'] = df['c1'] + df['c2'] # 创造新列并赋值
# 筛选
df.loc[ df.c1 > 0, ['c1', 'c2']]
# 赋值
df.iloc[0,1] = 3

    发表于2023-03-17

Ubuntu系统快速安装PyTorch

1. 下载conda
wget https://mirrors.tuna.tsinghua.edu.cn/anaconda/archive/Anaconda3-2021.11-Linux-x86_64.sh
2. 安装conda
bash Anaconda3-2021.11-Linux-x86_64.sh并按提示同意安装协议

3. 启动环境变量
source ~/.bashrc
4. 安装PyTorch
conda install pytorch torchvision torchaudio cudatoolkit=11.3 -c pytorch

    发表于2022-08-02

PyTorch使用cuda运算

主要使用torch.device()函数选择运行设备。

def try_gpu(i=0):
"""如果存在,则返回gpu(i),否则返回cpu()"""
if torch.cuda.device_count() >= i + 1:
return torch.device(f'cuda:{i}')
return torch.device('cpu')

torch.cuda.device_count()可以返回可用的cuda设备数量,torch.cuda.is_available()可以返回cuda是否可用。

    发表于2022-03-08

Python爬虫库requests简介

requests是Python的一个网络爬虫库。直接import即可使用:
import requests
设置html headers
headers = {'User-Agent':'Mozilla/5.0 (Windows NT 6.1; WOW64; rv:23.0) Gecko/20100101 Firefox/23.0'}

用Get方法爬取网页
url = zmw.ink #以本站为例
res = requests.get(url) #返回requests对象
res.encoding="utf-8" #设置utf-8编码
print(res.text) #返回文本格式的html内容

    发表于2022-03-01

利用SVD分解压缩图像

from PIL import Image
import numpy as np

# 利用SVD分解处理并返回压缩后的数据
def svd_approx(data, per): # data是数据矩阵,per代表处理的奇异值个数占比
if per > 1 or per < 0:
print("percentage error!")
return
U, s, VT = np.linalg.svd(data)
Sigma = np.zeros(np.shape(data))
Sigma[:len(s), :len(s)] = np.diag(s)
k = int(per * len(s))
D = U[:, :k] @ Sigma[:k, :k] @ VT[:k, :]
D[D < 0] = 0
D[D > 255] = 255
return np.rint(D).astype("uint8") # rint是根据四舍五入取整


# 导入图像,进行SVD压缩,输出图像
def rebuild_img(filename, per):
img = Image.open(filename)
data = np.array(img)
R, G, B = data[:, :, 0], data[:, :, 1], data[:, :, 2]
color = [R, G, B]
new_color = []
for color in [R, G, B]:
new_color.append(svd_approx(color, per))
I = np.stack(new_color, 2)
svae_name = str(round(per * 100, 0)) + ".jpg"
Image.fromarray(I).save(svae_name)
img = Image.open(svae_name)
img.show()

filename = "test.jpeg" #这里设置图像的文件名
for per in np.linspace(0.01, 1, 10): #这里选择保留特征值的占比
rebuild_img(filename, per)

    发表于2022-02-04

Numpy 线性代数

import numpy as np

# 通过列表或元组直接生成数组
A = [[1, 2, 3, 4], [5, 6 ,7, 8]]
B = ((1,2,3,4), (5,6,7,8))
arr1 = np.array(A)
arr2 = np.array(B)
print(A, arr1)
print(B, arr2)

#随机生成数组
arr1 = np.random.random((2,3)) #默认范围是[0,1]
arr2 = np.random.randint(1, 10, size=[2,3]) #随机生成整数
print(arr1, arr2)

# 通过reshape修改数组形状
arr1 = arr1.reshape(3, -1) #未知参数可用-1代替,这里是(3,2)
print(arr1)

# 数组的存取
C = np.arange(0, 12, 1) #生成range[0, 12, 1]的一维数组
C = C.reshape(3, 4) #修改形状
print(C)
print("C[1:2]=", C[1:2]) #1行2列元素,从0开始计数
print("C[0]=", C[0]) #第0行
print("C[ : ,0]=", C[:,0]) #第0列
print("C[1:2, 0:3:1]=", C[1:2, 0:3:1]) #以range(1,4,1)方式取列
print("C[1:2, [1, 2]=", C[1:2, [1, 2]]) # 以列表形式指定取哪些列
print("C[:, -1]=", C[:, -1]) #以负数形式指定倒数第几列,从-1开始计数
print("C[C > 5]=", C[C > 5]) #bool索引,C > 5返回一个bool类型的同型数组,输出为一维数组

# 生成特殊矩阵
z = np.zeros((3, 4)) #零矩阵
o = np.ones((3, 4)) #元素为1的矩阵
e = np.eye(3) #单位矩阵
d = np.diag([1,2,3,4]) #对角矩阵
print(z, o, e, d)
print(np.diag(z)) #取矩阵的主对角元

# 数组的广播机制
# 广播是对不同形状 的数组进行计算的方法
# 当两个不同型的数组计算时,会先通过复制得到新数组来计算
a = np.array([[1, 2, 3, 4], [5, 6, 7, 8]])
b = np.ones((1,4))
print(a*b, a+b)

# 二维数组(矩阵)的乘法
A = np.arange(12).reshape(3,4)
B = np.ones((3,4))
print(A * B) # 按元素相乘
print(A @ B.T) # 按矩阵意义相乘, .T代表转置

# 逆矩阵, 行列式, 矩阵的秩
C = np.random.random(9).reshape(3, 3)
C_inv = np.linalg.inv(C) #求逆矩阵
E = np.round(np.array(C@C_inv), 0) #round是进行四舍五入
print(C, C_inv, E)

C = np.random.randint(0,10, size=[3,3])
print(C, "det=", np.linalg.det(C), 0) #求行列式
print("rank=", np.linalg.matrix_rank(C)) #求矩阵的秩

# 线性方程组的解
A = np.eye(3)
B = np.linspace(2,4,3)
X = np.linalg.solve(A, B) #Ax = B的解
print(X)

# 向量的欧氏度量
A = np.linspace(1, 3, 3) #依闭区间[1,3]创建一个3元的一维向量
B = np.linspace(4, 6, 3)
A_B = np.dot(A, B.T) #向量内积dot,必须是行向量与列向量相乘
print("A@B=", A_B)
A_norm = np.linalg.norm(A)
print("|A|=", A_norm)

# 特征值与特征向量
A = np.array([[4, 2], [1, 5]])
eig_val ,eig_vex = np.linalg.eig(A) #返回特征值与特征向量
print("eig_val=", eig_val, "\n eig_vex=", eig_vex)

# SVD分解
A = np.arange(12).reshape(3, 4)
U, S , V = np.linalg.svd(A) #返回U,奇异值s(向量),V 使得A=USV
Sigma = np.zeros(shape=np.shape(A))
Sigma[:len(S), :len(S)] = np.diag(S)
print("U=", U, "V=", V, "S=", S)
print("U@Sigma@V = ", np.round(U@Sigma@V, 0))

# 利用SVD重构矩阵
A = np.arange(100).reshape(10, -1)
U, S, V = np.linalg.svd(A)
k = 3 #只取前k个(最大的)特征值
Sigma = np.diag(S[:k])
_U = U[:, :k] #U取前k列
_V = V[:k, :] #V取前k行
print("压缩后的A = ", np.round(_U @ Sigma @ _V, 1))

    发表于2022-02-04

Numpy 微积分基础

import sympy
from sympy import *
from sympy.abc import x, y
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D

# 求极限
f = (x ** 2 - 1) / (x - 1)
print(sympy.limit(f, x, 1))

f = sympy.sin(x) / (3 * x + x ** 3)
lim = sympy.limit(f, x, 0)
print(lim)

# 求导数

print(sympy.exp(x))

# 求偏导
f = x ** 2 + 3 * x * y + y ** 2
fx = diff(f, x)
print(fx.evalf(subs={x: 1, y: 2})) # 以字典形式输入自变量


# 梯度下降法求函数最小值
def fun(x, y):
return x - y + 2 * x ** 2 + 2 * x * y + y ** 2
def px(x, y):
return 4 * x + 2 * y + 1
def py(x, y):
return -1 + 2 * x + 2 * y
fig = plt.figure() # 绘制3D图像
ax = Axes3D(fig)
X, Y = np.mgrid[-2:2:50j, -2:2:50j] # 生成n=2维矩阵,从-2到2(闭区间),共40个值
Z = fun(X, Y)
ax.plot_surface(X, Y, Z, rstride=1, cstride=1, cmap='rainbow')
plt.show()

x, y = 0, 0 # 初始化变量
lr = 0.01 # 定义学习率
z = fun(x, y)
epoch = 0 # 迭代次数
while True:
epoch += 1
n_x, n_y = x - lr * px(x, y), y - lr * py(x, y)
n_z = fun(n_x, n_y)
diff = z - n_z
print(f'epoch {epoch}: x={x}, y={y}, z={z}, diff={diff}')
if abs(diff) < 1e-9:
print(f'result: x={n_x}, y={n_y}')
break
x, y, z = n_x, n_y, n_z

#定积分
import numpy as np
from scipy.integrate import quad #单重积分
func = lambda x:np.cos(np.exp(x))**2 #被积分函数
solution = quad(func, 0, 3) #返回一个元组,第0项为结果,第1项为误差
print(solution[0])

    发表于2022-02-03

PyTorch自动微分

import torch
自动微分
# 对函数\(y=2x^tx\)求梯度,x为列向量
x = torch.arange(4.0)
# 寻找存储梯度的内存
x.requires_grad_(True)
print(x.grad)
y = 2 * torch.dot(x, x)
print(y)
# 调用反向传播函数backward()
y.backward()
print(x.grad)
# 验证
print(x.grad == 4 * x)
# 再计算另一个函数:y=x.sum()
# 需要先清除之前的值
x.grad.zero_()
y = x.sum()
y.backward()
print(x.grad)

分离计算
# 设y=y(x),z=z(x,y). z对x求偏导会受到y的影响
# 在一些情况下,我们希望将y视为常数,再求z对x的偏导,需要用到分离函数detach()
x.grad.zero_()
y = x * x
u = y.detach()
z = u * x
z.sum().backward()
print(x.grad)

    发表于2022-01-30

PyTorch 线性代数

import torch
向量:一维张量
x = torch.arange(4)
print(len(x)) # len(x)输出长度
# 矩阵:二维张量
A = torch.arange(20).reshape(5, 4)
print(A.T) # .T方法获取转置矩阵
B = A.clone()
print(A * B) # 这里的乘积是Hadamard积,即按元素乘积
矩阵的降维
print(A.sum()) # 默认沿所有轴降维,得到单元素张量
print(A.sum(axis=0)) # 沿第0轴降维,得到1*4张量
print(A.sum(axis=[0, 1])) # 沿0和1轴降维,效果同sum()
print(A.cumsum(axis=0)) # 沿第0轴求和,结果附在最后一行,不改变原值

向量的点乘:dot
x = torch.arange(4, dtype=torch.float)
y = torch.ones(4)
print(torch.dot(x, y))

矩阵与向量乘积:mv
A = torch.arange(20, dtype=torch.float).reshape(5, 4)
x = torch.arange(4, dtype=torch.float)
print(torch.mv(A, x))

矩阵乘法:mm
B = torch.ones(4, 3)
print(torch.mm(A, B))

范数
u = torch.tensor([3, 4], dtype=torch.float)
print(torch.norm(u)) # 默认是L_2范数
# 矩阵范数
X = torch.ones(4, 9)
print(torch.norm(X)) # 默认是L_2范数

    发表于2022-01-29

PyTorch Tensor(张量)入门

import torch

# 张量tenser
# arange:类似range[start,end,step]
x = torch.arange(12)
print(x)

# .shape, .numel() 获取张量的形状和总数
print(x.shape, x.numel())

# reshape() 改变张量的形状. 缺省量可以用-1代替
X = x.reshape(3, 4)
print(X)

# .zeros, .ones 生成特殊张量
print(torch.zeros(2, 3, 4))

# .randn 生成随机的、服从标准正态分布N(0,1)的张量
print(torch.randn(3, 4))

# 给定数据生成张量:逐行输入。注意tenser数据类型为浮点数
print(torch.tensor([[2, 1, 4, 3], [1, 2, 3, 4]]))


# 运算符
# 四则运算符与幂运算符视为按元素操作
x = torch.tensor([1, 2, 3, 4])
y = torch.tensor([1, 1, 1, 1])
print(x + y, x - y, x * y, x / y, x ** y)

# 幂运算函数也视为按元素操作
print(torch.exp(x))

# 利用cat()可将张量连结在一起, dim表示按第几个轴连结
X = torch.arange(12).reshape(3, 4)
Y = torch.arange(12, 24).reshape(3, 4)
print(torch.cat((X, Y), dim=0)) # 6*4张量
print(torch.cat((X, Y), dim=1)) # 3*8张量

# 逻辑运算符也逐元素操作,返回值为一同尺寸张量,每处的值为其运算结果
print(x == y)

# .sum()对所有元素求和,返回单元素张量
print(x.sum())

# 广播机制
# 以上运算均限制张量尺寸相同或者符合某些条件。当形状不同的张量运算时,会触发广播机制。
# 广播机制是指先复制元素来扩展这些运算的张量,在转换之后具有恰当的形状以便运算。
a = torch.arange(3).reshape((3, 1))
b = torch.arange(2).reshape((1, 2))
print(a, b, a + b)
# 以上运算中,a复制一列,b复制两行,按照得到的3*2矩阵运算

# 索引和切片
# 如同数组,张量中的元素可以通过索引访问,第一个为0,最后一个为-1
X = torch.arange(12).reshape(3, 4)
print(X[-1], X[1:3])

# 可以指定索引修改张量的值
X[1, 2] = 9
print(X)
X[0:2, :] = 100 # 同时修改多个索引位置的值
print(X)

# 节省内存
# 在torch的张量运算中,Y=Y+X会不必要地给Y分配新的内存
# 可以使用切片表示赋值以节省内存
Z = torch.zeros_like(Y) # zeros_like生成一个相同尺寸的零张量
print('id(Z) = ', id(Z)) # id(Z)表示Z的地址
Z[:] = X + Y # 切片法运算
print('id(Z) = ', id(Z)) # id(Z)表示Z的地址
# 使用X[:] = X + Y , X += Y也可以实现上述效果

# Tensor与NumPy的相互转换
A = X.numpy()
B = torch.tensor(A)
print(type(A), type(B))

# 调用item()或Python内置函数将单元素张量转化为标量
a = torch.tensor([2022.1])
print(a, a.item(), float(a), int(a))

    发表于2022-01-29