《利用Python进行数据分析》 —— (2)

《利用Python进行数据分析》 —— (2)

本章主要介绍Python常用的数据结构和以及Python函数等基础知识。

3.1 数据结构与序列

3.1.1 元组

元祖是一种固定长度、不可变的Python对象序列

创建元组的方法:

In [3]: tup1 = 1, 2, 3 # 直接

In [4]: tup2 = (1, 2, 3), (4, 5) # 用括号分割

In [5]: tup3 = tuple([1, 2, 3]) # 利用tuple函数将任意序列或迭代器进行转化

In [6]: print(tup1, tup2, tup3)
(1, 2, 3) ((1, 2, 3), (4, 5)) (1, 2, 3)

元组一旦创建其各个位置上的对象无法被修改。但是假如元组中的对象是可变的,便可以对其进行修改,eg:列表

In [15]: tup = tuple([[1,2], [3]])

In [16]: tup
Out[16]: ([1, 2], [3])

In [17]: tup[0].append(4)

In [18]: tup
Out[18]: ([1, 2, 4], [3])

可以用+号连接元组来生成更长的元组。

3.1.1.1 元组拆包

如果将元组型的表达式赋值给变量,Python会对等式右边的值进行拆包:

In [21]: tup = (1, 2, 3)

In [22]: a, b, c = tup # 简单拆包

In [23]: print(a, b, c)
1 2 3

In [24]: tup1 = 4, 5, (6, 7)

In [25]: a, b, (c, d) = tup1 # 嵌套元组也行

In [26]: print(a, b, c, d)
4 5 6 7

使用这个功能,能够轻松的实现交换变量名

In [27]: a, b = 1, 2

In [28]: print(a, b)
1 2

In [29]: a, b = b, a # 进行交换

In [30]: print(a, b)
2 1

更为高级的拆包功能,“*rest用于在函数调用时获取任意长度的位置参数列表”rest变量名并不是保留字,可以替换。有时rest部分代表想要丢弃的数据,因此也可以用_下划线代表不想要的变量:

In [32]: a, b, *rest = val

In [33]: print(a, b, rest)
1 2 [3, 4, 5, 6]
3.1.1.2 元组方法

元组方法很少,常见可以使用的是count,用于统计某元素在元组中出现的次数。

3.1.2 列表

3.1.2.1 增加和删除元素

Noteremove方法会定位第一个符合要求的值并移除它。(区别于C++)

使用 innot 可以用于检查一个值是否在列表中。

但是与字典,集合相比检查列表是一个非常缓慢的过程,这是因为 Python 的手段是逐项检查。而在字典和集合中 Python 是同时检查所有元素(基于哈希表)

3.1.2.2 连接和联合列表

在尝试进行列表连接在一起时,extend 是比 + 更高效的办法。

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

内建的 bisect 模块实现了二分搜索和已排序列表的插值。

  • bisect.bisect会找到当前元素应当被插入的位置,并保持序列排序。
  • bisect.insort将元素直接插入到对应的位置。
In [63]: arr = [1, 2, 2, 2, 3, 4, 7]

In [64]: bisect.bisect(arr, 2) #二分查找
Out[64]: 4

In [65]: bisect.bisect(arr, 5)
Out[65]: 6

In [66]: bisect.insort(arr, 6) # 直接插入

In [67]: arr
Out[67]: [1, 2, 2, 2, 3, 4, 6, 7]

可以发现bisect.bisect在有重复元素时指向的是最右边的元素。因此在列表中存在重复元素时,可以考虑如下几个方法:

bisect.bisect_left bisect.insort_left

bisect.bisect_right bisect.insort_right

注意bisect方法并不会检查序列是否有序(开销过大),因此在使用前一定要排序(不然会出现错误答案)

3.1.2.5 切片

切片为 [start : stop] 并不包括最后一个 stop 位置。因此切片的元素长度为 stop - start

负数代表从后往前

切片还有一种语法为:[start : stop : step]

其中 step 代表没过多少步值取一个数,负数代表从后往前取

In [72]: arr
Out[72]: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

In [73]: arr[::2]
Out[73]: [0, 2, 4, 6, 8]

In [74]: arr[::-2]
Out[74]: [9, 7, 5, 3, 1]

In [75]: arr[::-1] # 实现了翻转
Out[75]: [9, 8, 7, 6, 5, 4, 3, 2, 1, 0]

3.1.3 内建序列函数

Python 中有许多序列函数,应当认真熟悉

3.1.3.1 enumerate

我们有时需要遍历一个序列的同时追踪当前元素的索引,面对这种场景我们可以使用Python 内建的 enumerate 函数,返回 (i, value) 元组的序列。例如:

In [78]: for i, val in enumerate(arr):
    ...:     print("{0:d}, {1:d}".format(i, val))
0, 0
1, 1
2, 2
3, 3
4, 4
5, 5
6, 6
7, 7
8, 8
9, 9
3.1.3.3 zip

zip 可以处理任意长度的序列,它生成列表的长度由最短的序列决定。

3.1.3.4 reversed

要记住 reversed 是一个生成器(后面详细介绍),只有实体化(即列表或for循 环)之后才能创建翻转的序列。(?? 不太懂先记录)

3.1.4 字典

可以通过 update 方法将两个字典合并,但是如果有相同的键值,则它的值会被新值覆盖

3.1.4.2 默认值

通常情况下,可能会出现这样的设计,我们先判断某个值是否存在于字典中假如不存在返回一个默认值:

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

例如,现在需要通过首字母将单词分类,在没有预设默认值的情况下得用 if-else 分支:

In [123]: words = ['apple', 'bat', 'bar', 'atom', 'book']
In [124]: by_letter = {}
In [125]: for word in words:
.....: 	      letter = word[0]
.....:        if letter not in by_letter:
.....: 		      by_letter[letter] = [word]
.....:        else:
.....:            by_letter[letter].append(word)
.....:
In [126]: by_letter
Out[126]: {'a': ['apple', 'atom'], 'b': ['bat', 'bar', 'book']}

通过setdefault可以快速解决这个问题:

for word in words:
	letter = word[0]
	by_letter.setdefault(letterm, []).append(word) # 设置默认为list

或者通过内建的defaultdict类实现默认值设置问题。传递类型或函数以生成每个位置的默认值:

from collections import defaultdict
by_letter = defaultdict(list) # 设置默认类型为list类型(可以设置为其他类型)
for word in words:
	by_letter[word[0]].append(word)
3.1.4.3 有效的键类型

只需要注意几点:值可以是任何 Python 对象,但是键必须是不可变的对象,(整数、浮点型、 字符串)或元组(元组中的对象必须是不可变的

3.1.5 集合

  • 集合的初始化操作

    • set([1, 2, 2, 3, 4])
    • {1, 2, 2, 3, 4}
  • 和字典类似,集合中的元素必须是不可变对象,因此假如想要包含列表元素,需要转化为元组类型。

set

3.1.6 列表、集合和字典推导式

关于一维推导式,记住以下三个经典的即可:

  • [expr for val in collection if condition]

  • dict_comp = {key-expr : value-expr for value in collection if condition}

  • set_comp = {expr for value in collection if condition}

关于多维嵌套列表推导式,只需要记住:for 表达式的顺序应与你写嵌套 for 循环来代替列表推导式的顺序一致。

3.2 函数

函数时对象,可以将函数操作存在一个列表中,直接调用,如下图所示:

In [99]: def f1(x):
    ...:     return x + 5

In [100]: def f2(x):
     ...:     return x ** 2

In [101]: def f3(x):
     ...:     return x * 3

In [102]: func = [f1, f2, f3]

In [103]: a = 1

In [107]: for funcs in func:
     ...:     a = funcs(a)

In [108]: a
Out[108]: 108
posted @ 2020-07-31 20:05  Last_Whisper  阅读(182)  评论(0编辑  收藏  举报