文章目录
完整代码
import os.path
import numpy as np
from torchvision.datasets import ImageFolder
from torch.utils.data import DataLoader
from torchvision import transforms
from sklearn.model_selection import train_test_split
def LoadMyData(dataroot):
transform = transforms.Compose([transforms.Resize((16,16)),transforms.ToTensor(),transforms.Normalize((0.5,0.5,0.5),(0.5,0.5,0.5))])
dataset = ImageFolder(dataroot,transform)
datafolder = DataLoader(dataset)
classes = []
labels = []
for myclass,mylabel in datafolder:
classes.append(myclass.view(-1).numpy())
labels.append(mylabel.item())
return classes,labels
def SplitData(data,labels):
x_train,x_test,y_train,y_test = train_test_split(data,labels,test_size=0.3,random_state=0)
return x_train,x_test,y_train,y_test
def PrepareData(dataroot):
classes,labels = LoadMyData(dataroot)
x_train,x_test,y_train,y_test = SplitData(classes,labels)
return x_train,x_test,y_train,y_test
def cal_distance(model,img1,img2):
if model == 'L1':
dis = sum(np.abs(img1-img2))
elif model == 'L2':
dis = np.sqrt(sum(np.square(img1-img2)))
return dis
def get_user_input():
print("请输入对距离的度量,L1表示曼哈顿距离,L2表示欧式距离:")
while(1):
mydis = input()
if mydis == 'L1':
model = 'L1'
return model
elif mydis == 'L2':
model = 'L2'
return model
else :
print("输入错误!请重新输入:")
def main(k,mydataroot):
model = get_user_input()
print("开始计算,请稍后")
dataroot = mydataroot
x_train, x_test, y_train, y_test = PrepareData(dataroot)
pred_y = np.empty((0,1))
for i in range(len(x_test)):
dis_list = np.empty((0,2))
for j in range(len(x_train)):
dis = cal_distance(model,x_test[i],x_train[j])
img_item = [[dis,y_train[j]]]
img_item = np.array(img_item)
dis_list = np.concatenate((dis_list,img_item))
distances = dis_list[:, 0]
index = np.argsort(distances)
sort_dis_list = dis_list[index]
k_sort_label_list = sort_dis_list[:,1][:k]
counts = np.bincount(k_sort_label_list.astype(int))
pred_label = np.argmax(counts)
pred_y = np.append(pred_y,pred_label).astype(int)
acc = np.mean(pred_y == np.array(y_test[:(i+1)])) * 100
print(f"共分类{i+1}张图像,当前准确率为{acc}%")
acc = np.mean(pred_y == np.array(y_test))*100
print(f"选择{k}个近邻的到的最终准确率为{acc}%")
if __name__ == "__main__":
dataroot = './data'
print("请输入选择的紧邻数量K值:")
k = input()
main(int(k),dataroot)
运行截图
代码解读
L1,L2距离
L1是曼哈顿距离,两个向量直接相减后取绝对值的加和。
L2是欧式距离,为两个向量相减后的方均根值
np.concatenate
np.concatenate是NumPy库中的一个函数,用于将两个或多个数组沿指定轴连接起来形成一个新的数组。它的语法如下:
numpy.concatenate((a1, a2, ...), axis=0, out=None)
(a1, a2, …):要连接的数组序列,可以是元组、列表或单独的数组。
axis:指定连接的轴。默认为0,表示沿着第一个轴连接,即在行方向上连接。如果指定为1,则表示沿着列方向连接。
out:可选参数,指定输出数组的存在位置。
np.concatenate的工作方式取决于指定的轴:
如果axis为0,则它将沿着行方向连接数组,即将数组垂直堆叠在一起,形成一个更大的数组。
如果axis为1,则它将沿着列方向连接数组,即将数组水平连接在一起,形成一个更宽的数组。
示例:
import numpy as np
# 连接两个一维数组
a = np.array([1, 2, 3])
b = np.array([4, 5, 6])
result = np.concatenate((a, b))
print(result)
# 输出: [1 2 3 4 5 6]
# 连接两个二维数组
c = np.array([[1, 2], [3, 4]])
d = np.array([[5, 6]])
result = np.concatenate((c, d), axis=0)
print(result)
# 输出:
# [[1 2]
# [3 4]
# [5 6]]
# 沿着列方向连接数组
e = np.array([[1, 2], [3, 4]])
f = np.array([[5, 6], [7, 8]])
result = np.concatenate((e, f), axis=1)
print(result)
# 输出:
# [[1 2 5 6]
# [3 4 7 8]]
np.empty
np.empty是NumPy库中的一个函数,用于创建一个指定形状和数据类型的未初始化的数组。它的语法如下:
numpy.empty(shape, dtype=float, order='C')
参数说明:
shape:表示所创建数组的形状的整数或整数元组。例如,要创建一个2行3列的数组,可以传递(2, 3)作为形状。
dtype:可选参数,表示所创建数组的数据类型。默认为float类型。可以使用NumPy中定义的数据类型,如int、float、bool等,或者通过指定字符串来表示特定的数据类型,如int32、float64等。
order:可选参数,表示数组在内存中的存储顺序。默认为’C’,表示按行的C语言顺序存储。也可以设置为’F’,表示按列的Fortran语言顺序存储。
np.empty函数创建一个未初始化的数组,其元素的初始值取决于内存的状态。由于未初始化,数组的内容可能是随机的,可能包含之前存储在相同内存位置上的值。因此,在使用np.empty创建数组后,需要确保通过其他方式对数组进行初始化或填充。
下面是一些示例,以说明np.empty的用法:
import numpy as np
# 创建一个形状为(3, 3)的未初始化数组
a = np.empty((3, 3))
print(a)
# 输出:
# [[4.67296746e-307 1.69121096e-306 2.78145741e-307]
# [1.89146896e-307 1.37961302e-306 6.23058028e-307]
# [1.02359848e-306 1.33510679e-306 6.23039354e-307]]
# 创建一个形状为(2, 2)的未初始化整数数组
b = np.empty((2, 2), dtype=int)
print(b)
# 输出:
# [[ 0 0]
# [1072693248 1073741824]]
# 创建一个形状为(2, 3, 4)的未初始化数组
c = np.empty((2, 3, 4))
print(c)
# 输出:
# [[[6.23042070e-307 1.33511018e-306 6.23052935e-307 1.86921279e-306]
# [1.60217812e-306 1.06810268e-306 1.42418172e-306 7.56601165e-307]
# [8.90104239e-307 1.33511969e-306 2.22522597e-306 1.06809792e-306]]
#
# [[8.06612616e-308 1.60219035e-306 1.37961302e-306 1.02360558e-306]
# [6.23061763e-307 1.11261502e-306
当创建空数组时,直接写为:
pred_y = np.empty((0,1)) #1列的空数组
dis_list = np.empty((0,2)) #2列的空数组(二维数组)
np.argsort
np.argsort是NumPy库中的一个函数,用于返回数组中元素排序后的索引值。它的语法如下:
numpy.argsort(a, axis=-1, kind=None, order=None)
参数说明:
a:要排序的数组。
axis:可选参数,表示沿着指定轴进行排序。默认为-1,表示沿着最后一个轴进行排序。
kind:可选参数,表示排序算法的种类。可以取值为’quicksort’、‘mergesort’、‘heapsort’。默认为None,表示使用默认的排序算法。
order:可选参数,表示要排序的字段。只有当数组是结构化数组时才有意义。
np.argsort函数返回一个数组,其中包含原始数组中每个元素排序后的索引值。这意味着返回的索引数组与原始数组具有相同的形状,但其值表示了原始数组中对应位置元素在排序后的位置。
下面是一些示例,以说明np.argsort的用法:
import numpy as np
# 一维数组的排序索引
a = np.array([3, 1, 2])
indices = np.argsort(a)
print(indices)
# 输出: [1 2 0]
# 原始数组为 [3, 1, 2],排序后为 [1, 2, 3],对应的索引为 [1, 2, 0]
# 二维数组按行排序的索引
b = np.array([[3, 1, 2], [6, 4, 5]])
row_indices = np.argsort(b, axis=1)
print(row_indices)
# 输出:
# [[1 2 0]
# [1 2 0]]
# 原始数组的第一行为 [3, 1, 2],排序后为 [1, 2, 3],对应的索引为 [1, 2, 0]
# 原始数组的第二行为 [6, 4, 5],排序后为 [4, 5, 6],对应的索引为 [1, 2, 0]
# 二维数组按列排序的索引
c = np.array([[3, 1, 2], [6, 4, 5]])
column_indices = np.argsort(c, axis=0)
print(column_indices)
# 输出:
# [[0 0 0]
# [1 1 1]]
# 原始数组的第一列为 [3, 6],排序后为 [3, 6],对应的索引为 [0, 1]
# 原始数组的第二列为 [1, 4],排序后为 [1, 4],对应的索引为 [0, 1]
# 原始数组的第三列为 [2, 5],排序后为 [2, 5],对应的索引为 [0, 1]
[:, k]和[:k]
1.[:, k]:这种形式的切片操作应用于二维数组(或矩阵)。:表示取所有行,k表示取第k列。例如,arr[:, 2]表示取所有行的第2列。
示例:
import numpy as np
arr = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
sliced = arr[:, 1] # 取所有行的第1列
print(sliced)
[2 5 8]
2.[:k]:这种形式的切片操作应用于一维数组。:表示从开头到结尾,k表示切片的结束索引(不包含在切片中)。例如,arr[:5]表示取数组的前5个元素。
示例:
import numpy as np
arr = np.array([1, 2, 3, 4, 5])
sliced = arr[:3] # 取数组的前3个元素
print(sliced)
[1 2 3]
嵌套列表-[[dis,y_train[j]]]和[dis,y_train[j]]的区别
如果希望将 dis 和 y_train[j] 作为一个整体添加到二维数组中,应该使用嵌套列表的方式。
在二维数组中,每个元素都应该是一个具有相同长度的一维子数组。因此,如果要将 dis 和 y_train[j] 作为一个整体添加到二维数组中,需要使用一个包含两个元素的子列表。
以下是一个示例代码,展示了如何使用嵌套列表的方式向二维数组添加新的项:
import numpy as np
dis = 1.5
y_train_j = 2
# 创建空的二维数组
my_array = np.empty((0, 2))
# 将 [dis, y_train[j]] 添加到二维数组中
new_item = [[dis, y_train_j]]
my_array = np.append(my_array, new_item, axis=0)
print(my_array)
# 输出:
# [[1.5 2. ]]
在这个示例中,我们创建了一个空的二维数组 my_array,然后使用嵌套列表的方式创建了一个新的子列表 new_item,其中包含要添加的元素 [dis, y_train[j]]。然后,我们使用 np.append() 函数将 new_item 添加到 my_array 中,并指定 axis=0 参数以沿着行的方向添加。
在使用 np.append() 函数将新的项添加到二维数组时,需要确保新的项具有相同的维度和形状。直接使用 [dis, y_train_j] 创建的对象是一个一维列表,而不是一个二维列表。因此,它不能直接添加到二维数组中。
np.append() 函数期望传递具有相同形状的数组作为参数进行连接。当我们在二维数组中添加新的项时,我们需要确保新的项是一个二维列表(即包含一个子列表)。
在之前的示例代码中,我们使用了 [[dis, y_train_j]] 创建了一个嵌套的列表(二维列表),这个嵌套的列表作为新的项添加到二维数组中。这样,我们可以确保新的项的形状和维度与二维数组相匹配。
如果直接使用 [dis, y_train_j],则它是一个一维列表,无法直接添加到二维数组中。您可以尝试使用 np.reshape() 或 np.expand_dims() 函数来将一维列表转换为二维列表,然后再进行添加操作。
和列表append()的区别
在 NumPy 中,np.append() 函数在执行添加操作时,要求添加的元素和原始数组具有相同的形状(shape)或维度(dimension)。这意味着添加的元素需要与原始数组在维度和形状上匹配,以便正确地执行连接操作。
当使用 np.append() 函数添加元素时,它会创建一个新的数组,并将原始数组和要添加的元素连接在一起。要求连接的数组具有相同的形状或维度是为了确保数据的一致性。
在列表中添加元素时,我们可以直接使用 append 函数来添加单个元素,而不必使用 append 函数加上中括号的形式 append([元素])。
这是因为列表是 Python 中的内置数据结构,可以直接处理各种对象。append 函数旨在将指定的元素添加到列表的末尾,而不需要将元素放在另一个列表中。
np.astype
在 NumPy 中,np.astype() 是用于将数组的数据类型(dtype)进行转换的函数。它返回一个新的数组,其中的元素类型被转换为指定的数据类型。
astype() 函数可以接受一个数据类型作为参数,用于指定转换后的数据类型。这个数据类型可以是 Python 的内置数据类型(例如 int、float、str 等),也可以是 NumPy 定义的数据类型(例如 np.int32、np.float64 等)。以下是一个示例代码,演示了如何使用 astype() 函数进行数据类型转换:
import numpy as np
# 创建一个包含整数的数组
my_array = np.array([1, 2, 3, 4, 5])
# 将数组的数据类型转换为浮点数类型
float_array = my_array.astype(float)
print(float_array)
# 输出: [1. 2. 3. 4. 5.]
print(float_array.dtype)
# 输出: float64