字典回顾

在Python中,字典是一个无序的、可变的数据类型,用于存储键(keys)和值(values)之间的映射关系。字典使用键来访问数据,与列表不同,不是使用索引来访问数据。

字典的主要特点包括:

  1. 字典由一系列键(keys)和值(values)组成,每个键映射一个值。
  2. 字典中的键必须是 不可变 对象,如字符串、数字、元组等,而值可以是任意对象。
  3. 字典是无序的,不支持索引,可以通过键查找值。
  4. 字典使用大括号{}来表示,每个键值对之间用逗号分隔。
  5. 字典是可变的,可以添加、删除、修改键值对。
  6. 字典长度可以使用内置的len()函数来计算,即键值对的个数。

字典操作

创建字典

1
2
3
4
5
#创建一个空字典
my_dict = {}

#带键值对的字典
my_dict = {'name': 'John', 'age': 25, 'city': 'New York'}

访问字典的值

1
2
my_dict['name']           #输出 'John'
my_dict.getdefault('gender','unknown') #输出 'unknown'

修改字典

1
2
my_dict['age'] = 26       #更新 'age' 的值为 26
my_dict.update({'city': 'San Francisco'}) #更新 'city' 的值为 'San Francisco

删除字典

1
2
3
4
del my_dict['name']          #删除 'name'键值
my_dict.pop('age') #删除 'age'键值
my_dict.clear() #清空字典
del my_dict #删除字典

遍历字典

字典的遍历不保证顺序,如果需要有序地遍历字典,请使用内置库 collections 中的 OrderedDict 类型。

1
2
3
4
5
6
7
8
9
10
11
# 遍历所有键值对
for key, value in my_dict.items():
print(key, value)

# 遍历所有键
for key in my_dict.keys():
print(key)

#遍历所有值
for value in my_dict.values():
print(value)

鸢尾花分类问题

下载 iris_training.csv (1.0kB)
下载 iris_testing.csv (3.6kB)

原版代码(77行):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
# 导入Pandas库
import pandas as pd

#将山鸢尾、变色鸢尾和维吉尼亚鸢尾名称使用列表iris_type存储
iris_type = ['Iris-setosa','Iris-versicolor','Iris-virginica']

#初始化三个列表,分别存储三种鸢尾花每个属性的总值和训练样本数量
setosa_sum = [0,0,0,0,0] #山鸢尾
versicolor_sum = [0,0,0,0,0] #变色鸢尾
virginica_sum = [0,0,0,0,0] #维吉尼亚鸢尾

#设置四个常量,分别代表三个列表的索引位所对应的含义
se_len = 2 #列表第0位代表萼片长度
se_wid = 3 #列表第1位代表萼片宽度
pe_len = 0 #列表第2位代表花瓣长度
pe_wid = 1 #列表第3位代表花瓣宽度
amount = 4 #列表第4位代表鸢尾花训练样本的数量

########训练阶段##############
#通过pandas的read_csv函数读入训练集数据文件‘iris_training.csv’
trainData = pd.read_csv('iris_training.csv')

#循环读取训练集CSV文件中的每一条训练数据,并进行处理
#分别累加计算每种类型鸢尾花的四个属性的总值,以及训练样本数量
for index, row in trainData.iterrows():
if row.classification == 'Iris-setosa':
setosa_sum[se_len] += row.se_len #萼片长度
setosa_sum[se_wid] += row.se_wid #萼片宽度
setosa_sum[pe_len] += row.pe_len #花瓣长度
setosa_sum[pe_wid] += row.pe_wid #花瓣宽度
setosa_sum[amount] += 1 #样本数量
elif row.classification == 'Iris-versicolor':
versicolor_sum[se_len] += row.se_len
versicolor_sum[se_wid] += row.se_wid
versicolor_sum[pe_len] += row.pe_len
versicolor_sum[pe_wid] += row.pe_wid
versicolor_sum[amount] += 1
elif row.classification == 'Iris-virginica':
virginica_sum[se_len] += row.se_len
virginica_sum[se_wid] += row.se_wid
virginica_sum[pe_len] += row.pe_len
virginica_sum[pe_wid] += row.pe_wid
virginica_sum[amount] += 1

########预测阶段##############
#通过pandas的read_csv函数读入测试集数据文件‘iris_testing.csv’
TestData = pd.read_csv('iris_testing.csv')

# 循环读取测试集CSV文件中的每一条训练数据,并进行处理
for index, row in TestData.iterrows():

#分别计算输入数据与三种鸢尾花均值的欧氏距离,存储在列表distance中
distance = []
distance.append( (row.se_len - setosa_sum[se_len]/setosa_sum[amount]) ** 2 \
+ (row.se_wid - setosa_sum[se_wid]/setosa_sum[amount]) ** 2 \
+ (row.pe_len - setosa_sum[pe_len]/setosa_sum[amount]) ** 2 \
+ (row.pe_wid - setosa_sum[pe_wid]/setosa_sum[amount]) ** 2)

distance.append( (row.se_len - versicolor_sum[se_len]/versicolor_sum[amount]) ** 2 \
+ (row.se_wid - versicolor_sum[se_wid]/versicolor_sum[amount]) ** 2 \
+ (row.pe_len - versicolor_sum[pe_len]/versicolor_sum[amount]) ** 2 \
+ (row.pe_wid - versicolor_sum[pe_wid]/versicolor_sum[amount]) ** 2)

distance.append( (row.se_len - virginica_sum[se_len]/virginica_sum[amount]) ** 2 \
+ (row.se_wid - virginica_sum[se_wid]/virginica_sum[amount]) ** 2 \
+ (row.pe_len - virginica_sum[pe_len]/virginica_sum[amount]) ** 2 \
+ (row.pe_wid - virginica_sum[pe_wid]/virginica_sum[amount]) ** 2)

# 获取最小的距离值
min_distance = min(distance)

# 获取最小的距离值的序号
idx = distance.index(min_distance)

# 将iris_type列表中对应序号位置的分类信息作为预测分类结果
# 打印当前样本实际分类和预测的分类
print('实际分类:',row.classification,'; 预测分类:',iris_type[idx])

修改版(50行):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
# 导入Pandas库
import pandas as pd

#将山鸢尾、变色鸢尾和维吉尼亚鸢尾名称使用列表iris_type存储
iris_type = ['Iris-setosa','Iris-versicolor','Iris-virginica']
iris_features = ["se_len","se_wid","pe_len","pe_wid"]

# 使用一个字典保存所有内容,并初始化所有名称为空字典
sum_dict = {}
for classification in iris_type:
sum_dict[classification] = {}


########训练阶段##############
#通过pandas的read_csv函数读入训练集数据文件‘iris_training.csv’
trainData = pd.read_csv('iris_training.csv')

#循环读取训练集CSV文件中的每一条训练数据,并进行处理
#分别累加计算每种类型鸢尾花的四个属性的总值,以及训练样本数量
for index, row in trainData.iterrows():
dict_class = sum_dict[row.classification]
for feature in iris_features:
dict_class[feature] = dict_class.setdefault(feature,0)+row[feature]
dict_class["amount"] = dict_class.setdefault("amount",0)+1


########预测阶段##############
#通过pandas的read_csv函数读入测试集数据文件‘iris_testing.csv’
TestData = pd.read_csv('iris_testing.csv')

# 循环读取测试集CSV文件中的每一条训练数据,并进行处理
for index, row in TestData.iterrows():
#分别计算输入数据与三种鸢尾花均值的欧氏距离,存储在列表distance中
distance = []
for classification in iris_type:
distance.append(
sum(
[row.se_len - sum_dict[classification][feature]/sum_dict[classification]["amount"]**2
for feature in iris_features]
)
)

# 获取最小的距离值
min_distance = min(distance)
# 获取最小的距离值的序号
idx = distance.index(min_distance)

# 将iris_type列表中对应序号位置的分类信息作为预测分类结果
# 打印当前样本实际分类和预测的分类
print('实际分类:',row.classification,'; 预测分类:',iris_type[idx])

说明

作为一份合格的代码,应该有良好的可读性和可拓展性。

不像原版分别对每一种鸢尾花进行单独编码,对每一种属性单独写出语句,在修改版代码中使用两个列表分别储存了鸢尾花的种类和属性。如果要增加鸢尾花的种类,或增加鸢尾花的属性,修改版后的代码只需修改列表即可正常工作。

并且,可读性也有较大的提高。比起原版,修改版的核心代码更专注于逻辑:

训练阶段核心代码只有四行。

1
2
3
4
dict_class = sum_dict[row.classification]
for feature in iris_features:
dict_class[feature] = dict_class.setdefault(feature,0)+row[feature]
dict_class["amount"] = dict_class.setdefault("amount",0)+1

比起原版对每一个属性单独统计,这样的代码更为简洁,也有更佳的可读性。

预测阶段核心代码只有两行(为了可读性换行到七行):

1
2
3
4
5
6
7
for classification in iris_type:
distance.append(
sum(
[row.se_len - sum_dict[classification][feature]/sum_dict[classification]["amount"]**2
for feature in iris_features]
)
)

比起原版对每一种鸢尾花都写一段代码,我们通过循环,消灭了代码中的重复部分。并使用 sum 对列表推导式求和,实现了一行完成求出欧氏距离的平方的功能。