Python数据分析 | (2)Python数据结构和序列

本篇博客所有示例使用Jupyter NoteBook演示。

Python数据分析系列笔记基于:利用Python进行数据分析(第2版)  

 

目录

1.元组

2.列表

3.序列函数

4.字典

5.集合

6.列表、集合和字典推导式

7.嵌套列表推导式


1.元组

元组是一个有固定长度且不可改变的Python序列对象。

  • 创建元组
t1 = (1,2,3)  #简单元组  用()包围 ,分隔元素
print(t1)
t2 = ((1,2,3),(4,5)) #元组的元素可以是另一个元组 也可以是其他任意类型
print(t2)
#可以将任意序列或迭代器 利用tuple()转换为元组
t3 = tuple([1,2,3,5.5]) #将列表转换为元组
print(t3)
t4 = tuple('string') #将字符串转换为元组
print(t4)

  • 元组的访问
print(t4)
print(t4[0])   #[]加索引进行访问,索引从0开始。
print("-----------")
t5 = tuple(['foo',[1,2],True])
print(t5)
try:
    t5[2] = False #一旦创建了元组,元组中的对象就不能修改了
except:
    print("一旦创建了元组,元组中的对象就不能修改了")
t5[1].append(3)  #如果元组中的某个对象是可变的 如列表,那么可以在原位进行修改
print(t5)
print("-----------")
#使用+/*可以串联元组
t6 = (1,2,'foo')
t7 = (None,7.8)
t8 = ('bar',)
print(t6+t7+t8)
print(4*t6)

  • 拆分元组
tup = (4,5,6)
a,b,c = tup #Python会对等号右侧的元组进行拆分 
print(a,b,c)
print("-----------------------------")
tup = (4,5,(7,8)) #当元组中的元素是元组类型时 也可以
a,b,(c,d) = tup
print(a,b,c,d)
print("-----------------------------")
#利用这个功能可以轻松的替换变量的名字
#C语言实现方式
tmp = a
a = b
b = tmp
#Python实现方式
a,b = 1,2
b,a = a,b
print(a,b)

变量拆分常用来迭代元组或列表,或者从函数返回多个值(之后会讲):

seq = [(1,2,3),(4,5,6),(7,8,9)]
for a,b,c in seq:
    print("a={0},b={1},c={2}".format(a,b,c))

高级元组拆分功能,从元组的开头“摘取”几个元素。使用特殊语法*rest,也用在函数签名中以抓取任意长度列表的位置参数:

values = (1,2,3,4,5)  #()可以省略
a,b,*rest = values 
print(a,b)
print(rest) 
#rest是舍弃的部分,名字不重要 一般会将不需要的变量用_表示
a,b,*_ = values

  • tuple方法

元组的大小和内容不能修改,它的实例方法都很轻量。

有一个很有用的方法count(也可用于列表),可以统计某个值出现的频率:

a = (1,2,2,2,3,4,2)
print(a.count(2))

2.列表

与元组相比,列表的长度和内容都是可变的。

  • 创建列表
alist = [1,2,3,'doo',None] #使用[]定义
print(alist)
print("------------------")
tup = (1,2,3)
alist = list(tup)       #也可以用list()创建
blist = list('string')
print(alist)
print(blist)
print("------------------")
print(blist[1])   #用[]加索引访问 从0开始 并可以修改
blist[1] = 'sssss'
print(blist)

列表和元组语义相近,很多函数可以交叉使用。

list()常用来在数据处理中实体化迭代器或生成器:

gen = range(10)
print(gen)  #迭代器
print(list(gen)) #实体化迭代器

  • 添加和删除元素
#append()可以在列表末尾添加元素
a1 = ['aa','foo','cat']
a1.append('dog')
print(a1)
print("------------")
a1.append(['mouse','tiger']) #也可以追加一个列表 作为当前列表的一个元素
print(a1)
print("---------------------")
#insert()可以在特定位置插入一个元素
a1.insert(1,'red')
print(a1)

注意使用insert()时,插入的序号必须在0和列表长度之间。与append相比,insert耗费的计算量更大,因为对后续元素的引用必须在内部迁移,以便为新元素提供空间。如果要在序列的头部和尾部插入元素,可能需要使用collections.deque,一个双尾部队列。

#insert()的逆函数pop() 可以返回并删除指定位置的元素
alist = ['foo','cat','red','tiger']
print(alist.pop(2))
print(alist)
print("---------------------")
#remove()可以去除某个值,只能去除第一次出现的该值
alist.append('foo')
print(alist)
alist.remove('foo')
print(alist)

如果不考虑性能,使用append和remove,可以把Python列表当作完美的“多重集”数据结构。

print(alist)
print('cat' in alist) #使用in 判断某个元素是否在列表中
print('dog' not in alist) #使用not in 判断某个元素是否不再列表中

在列表中检查是否存在某个值远比字典和集合速度慢,因为Python是线性搜索列表中的值,但在字典和集合中,在同样的时间内还可以检查其他项(基于哈希表).

  • 串联和组合列表
l1 = [1,2,[3,4],'foo',None]
l2 = [(3,4),6,8.7]
print(l1+l2)     #和元组一样可以使用 + 串联两个列表
print("-------------------------")
#也可以使用extend()
l1.extend(l2)
print(l1)

通过加法将列表串联的计算量比较大,因为要新建一个列表,并且要复制对象。用extend串联列表,尤其是到一个大列表中,更为可取,因此推荐下面的方法1:

方法1:

everything = []
for l in list_of_lists:  #list_of_lists  是一个大列表 列表中的元素是列表类型
    everything.extend(l)
    

方法2:


everything = []
for l in list_of_lists:  #list_of_lists  是一个大列表 列表中的元素是列表类型
    everything+=l
  • 排序
a = [7,2,5,1,3]
a.sort()
print(a) #sort() 可以对列表原地进行排序  不需要创建新对象
print("---------------------")
#sort()的参数key  2级排序
#比如按字符串长度对列表进行排序
b = ['aaa','tiger','momentum','a','cc']
b.sort(key=len)
print(b)

之后学习的sorted函数,可以产生一个排好序的序列副本。

 

  • 二分搜索和维护已排序的列表

bisect模型支持2分查找,和向已排序的列表中插入值。bisect.bisect返回要插入的值应该在的位置,bisect.insort保证列表顺序的前提下,向列表插入值:

import bisect
c = [1,2,2,2,3,4,7]
bisect.insort(c,5.5)   #保证列表顺序 在合适的位置插入元素
print(c)
print("---------------------")
print(bisect.bisect(c,5.5))  #如果在c中插入该值  应该在的位置
print(bisect.bisect(c,100))  #如果在c中插入该值  应该在的位置

注意:bisect不会自动检查列表是否已排好序,进行检查的话会耗费大量计算。因此,对未排序的列表使用bisect不会产生错误,但结果不一定正确。

 

  • 切片

切片可以选取大多数序列类型的一部分。基本形式[start:stop:step].切片包括起始元素,不包括结束元素,结果中包含的元素个数为stop-start。

seq = [7,2,3,7,5,6,0,1]
print(seq[1:5])   #不包含stop 1-4
print("--------------------")
print(seq)
seq[3:4] = [100,101]  #用序列为切片赋值 包括stop
print(seq)
print("----------------------")
#start 或 stop可以省略 默认为序列的开头或结尾
print(seq[:5])
print(seq[3:])
print("----------------------")
#负数表示从后向前切片   最后一个元素是-1  倒数第二个是-2  依次
print(seq[-4:])  #从倒数第4个元素到最后
print(seq[-6:-2]) #从倒数第6到倒数第3  (不包括stop)
print(seq[:-2])   #从头到倒数第3个元素  (不包括stop)

下图展示了正整数和负整数切片。标示在边缘的数字表明切片是在哪里开始开始哪里结束:

print(seq)
print(seq[::2]) #step可以设置步长  隔一个取一个
print("-----------------")
print(seq[::-1])  #最简单的逆序 列表、元组或字符串的方法

3.序列函数

  • enumerate函数

迭代一个序列时,可能还需要跟踪当前项的序号。Python内建的enumerate函数返回一个(i,value)元组序列:

for i, value in enumerate(collection):
    #do sth with value

当索引数据时,使用enumerate的一个好方法是计算序列(唯一的)dict映射到位置的值:

some_list = ['foo','bar','baz']
mapping = {}
for i,v in enumerate(some_list):
    mapping[v] = i
print(mapping)

  • sorted函数

对一个无序的序列(如列表,元组,字符串等),返回一个排好序的列表:

print(sorted((100,1,2,1)))
print(sorted([9,7,9,5,6,10,23,3,1]))
print(sorted('string,horse'))

sorted函数可以接受和sort相同的参数。

  • zip函数

zip可以将多个列表、元组或其他序列成对组合成一个元组列表:

seq1 = ['foo','bar','baz']
seq2 = ['one','two','three']
zipped = zip(seq1,seq2)
print(list(zipped))

zip可以处理任意多的序列,元素的个数取决于最短的序列:

seq3 = [True,False]
print(list(zip(seq1,seq2,seq3)))

zip最常见用法之一是同时迭代多个序列,可结合enumerate使用:

for i,(a,b) in enumerate(zip(seq1,seq2)):
    print('{0}:{1},{2}'.format(i,a,b))

给出一个“被压缩”的序列,zip可以被用来解压序列。可以看作把行的列表转换为列的列表:

pithers = [('duzhen','zhang'),('heng','zhang'),('chao','ma')]
first_names,last_names = zip(*pithers)
print(first_names)
print(last_names)

  • reversed函数

可以从后向前迭代一个序列:

reversed是一个生成器,之后会详细学习,只有实体化(即列表或for循环)之后才能创建翻转的序列。

4.字典

字典是Python中最为重要的数据结构,也被称作哈希映射或关联数组。它是键值对的大小可变集合,键和值都是Python对象。

  • 创建字典
#使用{}创建字典,键和值之间用:分开
d1 = {'a':'momentum','b':[1,2,3,4]}
print(d1)
print("------------------")
#可以像访问其他序列一样 访问、修改字典中的元素 或插入元素到字典中
print(d1['a']) #访问
d1['b'] = [1,2,3] #修改
print(d1)
d1[7] = 'an interge' #插入
print(d1)

 

print(d1)
#使用in判断字典中是否存在某个键
print(7 in d1)
print("---------------------")
#del语句可以删除字典中的某个键值对
d1[5] = 'some value'
d1['cat'] = 'another value'
print(d1)
del d1[5]
print(d1)
print("----------------------")
#pop函数可以删除字典中的某个键值对 并返回值
ret = d1.pop('cat')
print(ret)
print(d1)

keys、values和items函数是字典键和值的迭代器方法。实体化需要使用for循环或list()等:

print(d1)
print(list(d1.keys()))
print(list(d1.values()))
print(list(d1.items()))

update函数可以将一个字典和另一个字典融合:

print(d1)
d1.update({'x':'foo',1:2})
print(d1)
d1.update({'a':'xxx'}) #如果出现和原字典相同的键 就对其值进行更新
print(d1)

update函数是原地改变字典,因此任何传递给update的键的旧的值都会被覆盖。

  • 用序列创建字典

将两个序列配对组合成字典:

mapping ={}
for key,value in zip(key_list,value_list):
    mapping[key] = value

字典本质上是2元元组的集合,dict可以接受2元元组的列表:

mapping = dict(zip(range(5),reversed(range(5))))
print(mapping)

后面会学习dict comprehensions,另一种构建字典的优雅方式。

  • 默认值

下面是一个很常见的逻辑:

if key in some_dict:
    value = some_dict[key]
else:
    value = default_value

dict的get函数和pop函数可以取默认值并返回,因此上述if语句可以简写:

value = some_dict.get(key,default_value)

如何不存在键,get默认返回None,pop会抛出一个异常。

 

关于设定值,常见的情况是字典中的值属于其他集合,如列表。比如,你可以通过首字母将一个列表中的单词分类:

words = ['apple','bar','book','baz','atom']
by_letters = {}
for word in words:
    letter = word[0]
    if letter not in by_letters:
        by_letters[letter] = [word]
    else:
        by_letters[letter].append(word)
print(by_letters)

可以使用setdefault函数进行简写:

words = ['apple','bar','book','baz','atom']
by_letters = {}
for word in words:
    letter = word[0]
    by_letters.setdefault(letter,[]).append(word)
print(by_letters)

collections模块中有一个很有用的类,defaultdict,可以进一步简化。传递类型或函数以生成每个位置的默认值:

from collections import defaultdict
words = ['apple','bar','book','baz','atom']
by_letters = defaultdict(list)
for word in words:
    by_letters[word[0]].append(word)
print(by_letters)

  • 有效的键类型

字典中的值可以是任意Python类型,而键通常是不可变得标量类型(整数,浮点数,字符串)或元组(元组中的对象必须是不可变得)。这被称为“可哈希性”。

可以用hash函数检查一个对象是否可哈希,即是否可被用作字典的键:

print(hash('string'))
print(hash((1,2,(2,3))))
print(hash((1,2,[2,3])))

要用列表当键,一种做法是把列表转为元组,只要内部元素可哈希,他也就可哈希:

d = {}
d[tuple([1,2,3])] = 5
print(d)

5.集合

集合是无序的不可重复的元素的集合。可以把它当作只有键的字典。

  • 集合的创建
#直接使用{}创建
a = {1,2,2,2,2,3,3,3}  #可以去重
print(a)
print("-------------")
#使用set()创建
b = set([1,2,2,3,3,3,4,5])  #可以去重
print(b)

  • 集合的合并、交集、差分、对称差等数学集合运算
a = {1,2,3,4,5}
b = {3,4,5,6,7,8}
#求并集
print(a.union(b))
print(a|b)
print("----------------")
#求交集
print(a.intersection(b))
print(a&b)

常用的集合方法:

所有的逻辑集合操作都有另外的原地实现方法,可以直接用结果代替集合的内容,对于大的集合,效率很高:

print(a)
print(b)
print("----------------")
c = a.copy()
print(c)
c |= b  #计算c和b的并集 并赋给c
print(c)
print("----------------")
d = a.copy()
print(d)
d &= b #计算d和b的交集 并赋给d
print(d)

与字典类似,集合元素通常是不可变的(相当于字典的键,可哈希)。要获取类似列表的元素,必须先转为元组:

my_data = [1,2,3,4]
my_set = set(tuple(my_data))
print(my_set)

可以检查一个集合是否是另一个集合的子集或父集:

a_set = {1,2,3,4,5}
b_set = {1,2,3}
print(b_set.issubset(a_set))
print(a_set.issuperset(b_set))

只有集合内容相同,才对等:

6.列表、集合和字典推导式

列表推导式允许用户从一个集合过滤元素,形成列表,传递参数的过程中还可以修改元素,形式如下:

[expr for val in collection if condition]

等价于:

result = []
for val in collection:
    if condition:
        result.append(expr)

给定一个字符串列表,可以过滤出长度>=2的字符串并转换为大写:

strings = ['a','as','bat','car','dove','python']
[x.upper() for x in strings if len(x)>=2]

同理,集合和字典的推导式如下:

set_comp = {expr for value in collection if condition}
dict_comp = {key_expr :value_expr for value in collection if condition}

用集合推导式,得到每个字符串的长度:

strings = ['a','as','bat','car','dove','python']
lengths = {len(x) for x in strings}
print(lengths)

使用map函数进一步简化:

strings = ['a','as','bat','car','dove','python']
lengths = set(map(len,strings))
print(lengths)

用字典推导式,创建一个字符串的查找映射表以确定它在列表中的位置:

strings = ['a','as','bat','car','dove','python']
loc_mapping = {val:index for index,val in enumerate(strings)}
print(loc_mapping)

7.嵌套列表推导式

假设有一个列表,它的元素也是列表,包含一些英文名和西班牙名,列表的第一个元素是一个列表包含所有英文名,第二个元素也是列表,把包含所有西班牙名。现在想用一个列表,把这些名字中包含>=2个e的名字找出来。

all_data = [['John','Ammy','eem','car'],['tttt','eeee','eee','aaaa']]
names_pro = []
for names in all_data:
    name_sin = [name for name in names if name.count('e')>=2]
    names_pro.extend(name_sin)
print(names_pro)
print("--------------------------")
#嵌套列表
names_pro1 = [name for names in all_data for name in names if name.count('e')>=2]
print(names_pro1)

嵌套列表推导式的for表达式顺序与嵌套for循环顺序一致,过滤条件还是放在最后。

将一个整数元组列表扁平化为一个整数列表:

some_tuples = [(1,2,3),(4,5,6),(7,8,9)]
flattened = [x for tuples in some_tuples for x in tuples]
print(flattened)

将一个整数元组列表转化为一个整数列表的列表:

some_tuples = [(1,2,3),(4,5,6),(7,8,9)]
flattened = [[x for x in tuples] for tuples in some_tuples]
print(flattened)

可以有任意多级别的嵌套,如果有两三个以上的嵌套,应该考虑代码可读性问题。分辨列表推导式中的语法很重要。

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值