第六周课程导学
本课概要:
当然我们经常会遇到的不是一个数据,而是一组数据,一组数据可以表达一个或多个含义。那么怎么让程序把
一组数据当成一个数据来处理呢?或者怎么能让程序更好地组织一组数据,这就是组合数据类型需要完成的任务。
组合数据类型有三种最重要的类型结构,它分别是集合类型、序列类型和字典类型
6.1 集合类型及操作
不可变数据类型:集合中的每一个元素,一旦放到集合中,这个元素是不能被修改的。比如像列表类型,列表类型
是可以被修改的数据类型,那么一旦这个数据类型放到集合中,那么集合就可能出错。
集合类型一定是由不可变数据类型组成的。集合类型它要求其中的元素是独一无二的,不能存在相同元素
集合类型天然要求不能存在可变数据类型的元素
集合用大括号{}建立
元组用小括号()建立
集合不能够包含相同的元素。由于给定的字符串中有两个相同的p和y,那么生成集合之后,相同的p和y将会被去掉。而生成之后,其中的元素也并不是按照pypy123的顺序来保留,因为集合中的元素之间没有顺序
集合用大括号{}表示,元素间用逗号分隔
集合中每个元素唯一,不存在相同元素
集合元素之间无序
集合操作符:
S^T:表示在S中也在T中,但不同时在S、B中的元素
集合处理方法:
我们知道方法它是用某个变量加个“.”,这样的方式来调用的函数
S.pop是从集合中随机取出一个元素,取出的概念就是把这个元素返回给用户,同时在集合中删除这个元素。如果
S是空的,那我取不出来任何元素,将返回KeyError异常
这里注意:由于集合元素是没有顺序的,所以使用for in 的形式,去返回获得的元素也是不确定的(不确定指的是用for
in的方式获取变量的时候,它可能与你定义的 顺序不同,但是一旦一个集合类型定义生成之后,它内部其实是有一个顺序的,只不过这个顺序对于程序员来讲,你是没发利用的,它是程序内部去保存集合时候所运用的一种顺序)
集合类型应用场景:
怎么判断某一个数据或其它一组数据,是否在这个数据中。这时我们需要用集合方式来表达这组数据,
并且对另外的数据或者一组数据与这一组数据之间的关系进行比较
数据去重
(将有重复元素的列表转变为无重复元素的列表)
将其它的数据类型变成列表,我们用set(ls),将列表ls变成一个集合S,那么S中就已经去掉了重复元素
如果我们希望仍然使用列表类型去处理这组数据,我们再用list函数将集合类型转变为列表类型
单元小结:
如果希望创建一个空集合,一定只能使用set函数
6.2 序列类型及操作
单元开篇:
**序列类型定义 **
序列是一维元素向量,元素类型可以不同
序列处理函数及方法
ls[::-1] 返回列表中所有元素,但是从元素最后向最前提取的一个子序列,它做的作用是将列表元素取反。
我们在字符串处理中,我们使用字符串的[::-1]对字符串取反。这是因为字符串类型本身也是序列类型的一种扩展形式
对于字符串这个序列,其中每个元素都是字符,那么字符之间的比较是按照字母序来比较,那么最大的字母序是y,
所以max(s)返回字符串‘y’
元组类型及操作
元组是一种序列类型,一旦创建就不能被修改
func()函数有两个返回值,比如return1,2。我们说在这个时候,函数返回了两个值1和2。事实上在Python内部,
它会认为函数返回了一个值,这个值是一个元组类型。我们说元组类型可以有小括号或者不使用小括号来创建,那么1,2
本身就是一个元组类型
元组类型就是将元素进行有序的排列,用“()”形式来组织。元组类型的每个元素一旦定义了,它的元素的每个值是不能改变的。元组类型继承了序列类型的全部通用操作(集合、元组不能修改;列表可以修改)**
注意:在使用creature[::-1]进行切片的时候,他并不改变原有creature变量的值,而是生成一个新的元组值。
比如color是由creature和另外两个元素构成的元组,我们可以使用方括号来进行索引操作,color[-1]会索引到creature
这个元素上,由于creature又是一个元组类型,他还可以继续使用[2]来进一步索引它的第二个元素,那么返回的值是
“tiger”
列表类型及操作
列表是一种序列类型,创建后可以随意被修改,各元素类型可以不同,无长度的限制。可以向其中随意的增加元素或减少元素,所以使用起来非常灵活
ls和lt都指向同一个列表。上面这种设计的真正原因,如果要简单说,比如这里面使用了内存、使用了指针,使用了更多的数据概念,但是我们把它再简化一下,在定义列表时如果我们使用了“[]”,或者使用了函数list,那么我们真正的创建了一个列表,如果没有使用“[]”或list,仅仅使用赋值,那么它只是将一段列表赋给了一个新的名字,相当于重新命名
del ls[::3] 表示删除以3为步长的列表子序列,那就是删除其中的3和1024这样的元素。
ls*2 表示的是对列表进行元素复制。这样的运算会作用到列表本身,所以列表ls会随着每次运算发生数据元素的变化
序列类型应用场景
序列包含元组、列表两种重要的扩展类型。序列类型最重要的应用场景是用来做数据表示。
其中元组用于元素不改变的应用场景,更多用于固定搭配场景
列表更加灵活,它是最常用的序列类型
对于列表用 for item in ls
对于元组用 for item in tp (tp是元组类型的一个变量)
我们可以使用tuple函数将它变为元组类型,这样后续的程序无论对它怎么操作,都不会改变它的数据值
为什么我需要去保护一段数据呢?难道我的程序不能保护我的数据吗?如果程序全部是由一个人来完成,那么你的数据完全由程序精确的管理和处理,这当然没有问题。但是如果我们有多人共同完成一段程序,我们又不希望我的数据,通过某些变量修改,那么你可以要求程序之间的接口,采用元组形式来传递,这样就能达到一定保护数据的目的
单元小结
列表操作由于可以更改其中的元素,所以在序列的基本操作之上,增加了更多的灵活处理的函数和方法
本章内容中序列类型是重点,而序列类型中列表类型又是重点
6.3 实例9:基本统计值计算
“基本统计值计算”问题分析
“基本统计值计算”实例讲解
计算中位数的函数需要对列表进行排序-----sorted()
# 返回列表
def getNum():
nums = []
iNumStr = input("请输入数字(回车退出)")
while iNumStr != "":
nums.append(eval(iNumStr))
iNumStr = input("请输入数字(回车退出)")
return nums # 返回列表
# 计算平均数
def mean(numbers):
s = 0.0
for num in numbers:
s = s + num
return s / len(numbers)
# 方差
def dev(numbers, means):
sdev = 0.0
for num in numbers:
sdev = sdev + (num - means) ** 2
# return pow(sdev / (len(numbers)-1), 0.5)
return pow(sdev / (len(numbers) - 1), 0.5)
# 中位数
def median(numbers):
sorted(numbers)
size = len(numbers)
if size % 2 == 0:
med = (numbers[size // 2 - 1] + numbers[size // 2]) / 2
else:
med = numbers[size // 2]
return med
n = getNum()
m = mean(n) # 计算平均值
print("平均值:{},方差:{:.2},中位数:{}".format(m, dev(n, m), median(n)))
基本统计值计算“举一反三”
6.4 字典类型及操作
1.单元开篇
我们已经学过了集合类型、序列类型,那么集合类型、序列类型和字典类型是组合类型的三种表达形式。学习了本单元,那么同学们就应该掌握了数据组合数据类型的全部的表达方法
2.字典类型定义
其中的每一个元素是由键和值通过冒号:表示,元素之间用“,”来分隔
其实这样的特点跟在序列类型中,通过一个列表“[]”,输入一个序号获得值是一样的,只不过在字典类型中序号是由用户来直接定义的,可以定义为像字符串这样的任何非可变类型。
如果是空集合,必须使用set()建立;空字典可以使用大括号{}表示
**重点:**集合类型与字典类型不同,集合类型中的每一个元素就是一个基本元素,它不是一个键值对。而字典类型的每一个元素是一个键值对。我们在集合类型中要求大家,如果生成一个空的集合类型,不能使用空“{}”的方式,这是因为空“{}”的方式是默认来生成字典类型的,因为字典类型在计算机编程中会非常常用,所以我们将“{}”空的形式,保留给生成空字典类型来使用。如果想生成空的集合类型,那就是用set函数来完成
3.字典处理函数及方法
k in d:k并不是数据值,而是数据值的索引
d.keys()和d.values() 并不返回列表类型,它返回的是一种字典的key类型,或字典的value类型。这些类型可以用for in的方式做遍历,但是不能当做列表类型来操作
d.pop函数也是返回键k对应的值,只不过它不是返回,是取出。取出之后要删除字典中对应的键值对。如果K不在字典d中,则返回后边的default的值。
因为巴基斯坦不是字典d中的索引,也就是不是字典d中键的信息。所以使用后面的默认值—“伊斯兰堡”
字典其中的元素并没有顺序关系,所以这里面说修改第2个元素指的是,你向之前向d中增加的第2个
元素,它的键值对是b和2,把它做相关的修改
4.字典类型应用场景
5.单元小结
6.5 模块5:jieba库的使用
jieba库是靠什么原理来进行中文分词的?我们知道词语与词语之间他都是由汉字来组成的,所以简单说jieba库是通过中文词库的方式来识别分词的。它首先利用中文词库,通过这样的词库计算汉字之间的构成词语的关联概率。比如中、文两个汉字,它们之间就有很强的概率构造成一个词组叫中文。所以通过计算汉字之间的概率就可以形成分词的
结果。当然除了jieba自带的中文词库,用户也可以向其中增加自定义的词组,从而使jieba的分词更适应某些具体领域的使用
jieba库使用说明
jieba库的要点是什么?就是一个函数jieba.lcut(s)。它能将字符串s进行精确的分词处理,并且返回一个
列表类型。只需要记住这样的一个函数就能够完成中文分词的功能
6.6 实例10:文本词频统计
1.“文本词频统计问题分析”
2. “Hamlet英文词频统计”实例讲解
hamletTxt.split(): 它默认的是采用空格将字符串中的信息进行分割,里面的每一个元素就是一个空格分开的单词。并且以列表的形式返回给变量。所以words是一个列表类型
我们需要定义字典类型,使用字典类型来表达单词跟出现频率之间的对应关系
我们逐一的去从words这个列表中,取出每一个元素,取出之后,我们尝试一下这个元素是否在counts中,这里面用到了一个counts中的方法,叫做counts.get.使用字典.get()方法,用来从字典中获得某一个键对应的值,如果这个键不存在在字典中,也就是尚未在字典中,我们给出默认值
字典,get()方法用来从字典中获得某一个键对应的值,如果这个键不存在在字典中,也就尚未在字典中,我们
给出默认值
counts.get(word,0)它指的是用当前的某一个英文单词作为键索引字典,如果它在里面,南无就返回它的次数,后面再加1,说明这个单词又出现了一次,如果这个单词不在这个字典中,那我们就把它加到字典中,并且赋给当前的值为0,那么0加1是1,因为这个单词出现过一次,那么counts前面的word等于counts.get+1就是等于0+1,相当于在字典中新增了一个元素。
这里从words这个列表中取出每一个元素,去除之后我们尝试一下这个元素是否在counts中
将字典类型转化为列表类型便于操作,对于列表类型使用它的sort方法
sort中的一个类型的lambda用来指定在列表中使用哪一个多元选项的列作为排序列,而默认的排序方法是从小到大,
reverse设为True,那么返回的排序就是从大到小。这个能完成的工作就是对一个列表按照键值对的2个元素的第2个元素进行排序,
排序的方式是由大到小的倒排
def getText():
txt = open("./hamlet", "r").read()
txt = txt.lower()
for ch in '!"#$%&()*+,-./:;<=>?@[\\]^_‘{|}~':
txt = txt.replace(ch, " ") # 将这些标点符号修改为空格
return txt
hamleTxt = getText()
words = hamleTxt.split() # 每个字符串中间都有个空格,那么我们可以通过这个空格来分隔这个字符串,并以列表的形式返回
counts = {}
for word in words:
counts[word] = counts.get(word, 0) + 1
items = list(counts.items()) # 为了方便,将counts字典变成列表形式
items.sort(key=lambda x: x[1], reverse=True)
for i in range(10):
word, count = items[i]
print("{0:<10}{1:>5}".format(word, count))
'''
冒号是引导符,后面跟的是格式控制方法。<表示左对齐,>表示右对齐,数字表示宽度。同理,题中<10表示左对齐,并占10个位置,>5表示右对齐,占5个位置。
'''
3.《三国演义》人物的出场统计“实例讲解(上)
《三国演义》和Hamlet不同,它是中文文本,首先要对中文进行分词,之前我们讲解过中文的分词库jieba,我们可以使用jieba来完成它。除了使用jieba进行分词,中文不存在大小写问题,所以大小写可以很好的处理,中文的标点符号会在分词的过程中都将会被处理掉,所以我们不需要处理特殊符号
# 《三国演义》人物出场统计初级版本
import jieba
txt = open("./threekingdoms.txt", "r", encoding="utf-8").read()
words = jieba.lcut(txt)
counts = {}
for word in words:
if len(word) == 1:
continue
else:
counts[word] = counts.get(word, 0) + 1
items = list(counts.items()) # 将字典转换为列表形式
items.sort(key=lambda x: x[1], reverse=True)
for i in range(15):
word, count = items[i]
print("{0:<10}{1:>5}".format(word, count))
4.《三国演义》人物的出场统计“实例讲解(下)
像上面的将军、却说、二人、玄德曰、孔明曰这些词都不是《三国演义》里出现的人名。
同时像诸葛亮、孔明曰和孔明其实是一个人,关公、云长跟关羽也是一个人,但是是不同的称谓,而
这种称谓之间应该关联起来。所以我们需要进一步完成的是在词频统计的基础上,怎么去面向问题改造我们的程序
我们要进行升级版,在这个升级版中我们要给出一些排除词库,也就是对于某些确定不是人名的词,即使
我们做了词频统计,我们也要把它删除掉。
理解这里面对排除词库以及对名称关联的处理方法
我们看到曹操、孔明、刘备等的人物出场次数已经发生了变化,那么之后还会有像“商议”,“如何”、“主公”,
“军士”这样的非人名词汇,所以我们也要进一步地将这样的词库加到我们排除词库中,进一步优化输出结果。
# 《三国演义》人物出场统计终极版本
import jieba
txt = open("./threekingdoms.txt", "r", encoding="utf-8").read()
excludes = {"将军", "却说", "荆州", "如何", "商议", "二人", "不可", "不能", "如此"}
words = jieba.lcut(txt) # 精确模式,返回一个列表类型的分词结果
counts = {}
for word in words:
if len(word) == 1:
continue
elif word == "诸葛亮" or word == "孔明曰":
rword = "孔明"
elif word == "关公" or word == "云长":
rword = "关羽"
elif word == "玄德" or word == "玄德曰":
rword = "刘备"
elif word == "孟德" or word == "丞相":
rword = "曹操"
else:
rword = word
counts[rword] = counts.get(rword, 0) + 1
for word in excludes:
del counts[word]
items = list(counts.items())
items.sort(key=lambda x: x[1], reverse=True)
for i in range(10):
word, count = items[i]
print("{0:<10}{1:>5}".format(word, count))
5.“文本词频统计”举一反三
除了做基本的词频分析、人物统计分析,进一步还可以对文本的词语或词汇绘制词云
文本词频统计实例是充分利用组合数据类型中的集合、序列以及字典完成功能的非常好的哦实例