利用python进行数据分析(重点、易忘点)---第三章

3 python的数据结构、函数与文件

3.1 数据结构与序列

3.1.1 元组

如果元组中的某个对象是可变的,比如列表,可以在原位进行修改。

python 复制代码
tup = tuple(['foo', [1, 2], True])
tup[1].append(3)
tup #('foo', [1, 2, 3], True)

一次设置多个变量并赋值。

python 复制代码
a,b = 1,2
# a=b,b=a 错误示范
a,b=b,a

Python最近新增了更多高级的元组拆分功能,允许从元组的开头"摘取"几个元素。它使用了特殊的语法*rest,这也用在函数签名中以抓取任意长度列表的位置参数。rest的部分是想要舍弃的部分,rest的名字不重要。作为惯用写法,许多Python程序员会将不需要的变量使用下划线。

python 复制代码
values = 1, 2, 3, 4, 5
a, b, *rest = values
a,b #输出(1,2)
rest #输出[3,4,5]
a, b, *_ = values
3.1.2 列表

列表的常见操作,append、insert、pop、remove、extend。

python 复制代码
b_list.append('dwarf')
b_list.insert(1, 'red')
a = b_list.pop(2) #删除的同时赋值
b_list.remove('foo')
x = [4, None, 'foo']
x.extend([7, 8, (2, 3)])
x #输出[4, None, 'foo', 7, 8, (2, 3)]
3.1.3 sort函数

sort有一些选项,有时会很好用。其中之一是二级排序key,可以用这个key进行排序。例如,我们可以按长度对字符串进行排序。(不加参数默认按文本字母顺序或数字大小排序)

python 复制代码
a = [7, 2, 5, 1, 3]
a.sort()
a #输出[1, 2, 3, 5, 7]
b = ['saw', 'small', 'He', 'foxes', 'six']
b.sort(key=len)
b #输出['He', 'saw', 'six', 'small', 'foxes']

sorted函数可以从任意序列的元素返回一个新的排好序的列表,sorted函数可以接受和sort相同的参数。

python 复制代码
In [87]: sorted([7, 1, 2, 6, 0, 3, 2])
Out[87]: [0, 1, 2, 2, 3, 6, 7]
In [88]: sorted('horse race')
Out[88]: [' ', 'a', 'c', 'e', 'e', 'h', 'o', 'r', 'r', 's']
In [89]: sorted(b,key=len) # b = ['saw', 'small', 'He', 'foxes', 'six']
Out[89]: ['He', 'saw', 'six', 'foxes', 'small']
3.1.4 切片

在第二个冒号后面使用step,可以隔一个取一个元素。一个聪明的方法是使用-1,它可以将列表或元组颠倒过来。

python 复制代码
seq = [7, 2, 3, 7, 5, 6, 0, 1]
seq[3:4] = [6, 3]
seq #输出[7, 2, 3, 6, 3, 5, 6, 0, 1]
seq[::2] #输出[7, 3, 3, 6, 1]
seq[::-1] #输出[1, 0, 6, 5, 3, 6, 3, 2, 7]
3.1.5 zip方法

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

python 复制代码
In [89]: seq1 = ['foo', 'bar', 'baz']
In [90]: seq2 = ['one', 'two', 'three']
In [91]: zipped = zip(seq1, seq2)
In [92]: list(zipped)
Out[92]: [('foo', 'one'), ('bar', 'two'), ('baz', 'three')]
​

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

python 复制代码
In [93]: seq3 = [False, True]
In [94]: list(zip(seq1, seq2, seq3))
Out[94]: [('foo', 'one', False), ('bar', 'two', True)]

给出一个"被压缩的"序列,zip可以被用来解压序列。也可以当作把行的列表转换为列的列表。这个方法看起来有点神奇:

python 复制代码
In [96]: pitchers = [('Nolan', 'Ryan'), ('Roger', 'Clemens'),
   ....:             ('Schilling', 'Curt')]
In [97]: first_names, last_names = zip(*pitchers)
In [98]: first_names
Out[98]: ('Nolan', 'Roger', 'Schilling')
In [99]: last_names
Out[99]: ('Ryan', 'Clemens', 'Curt')
3.1.6 range

range(10) 的类型是 range 对象。它在 Python 中属于内置的不可变序列类型,表示一个从 09 的整数序列(不包含上限 10)。它不会像列表那样立即生成所有元素,而是一个惰性的序列对象,只有在需要时才会计算具体的值,这使得它在需要大范围数字时也可以节省内存。

python 复制代码
range(10) # range(0, 10)
list(range(10)) #[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
tuple(range(10)) # (0, 1, 2, 3, 4, 5, 6, 7, 8, 9)
3.1.7 字典

字典的一些用法(del、pop、update)

python 复制代码
In [111]: d1
Out[111]: 
{'a': 'some value',
 'b': [1, 2, 3, 4],
 7: 'an integer',
 5: 'some value',
 'dummy': 'another value'}
In [112]: del d1[5] #根据key删除字典中某条元素
In [114]: ret = d1.pop('dummy') # 删除并把key对应的value赋值给变量
In [115]: ret
Out[115]: 'another value'
In [119]: d1.update({'b' : 'foo', 'c' : 12}) # update的用法
In [120]: d1
Out[120]: {'a': 'some value', 'b': 'foo', 7: 'an integer', 'c': 12}

keys和values 的一些需要注意的。

python 复制代码
list(d1.keys())  # ['a', 'b', 7]
d1.keys()  # dict_keys(['a', 'b', 7])
list(d1.values()) # ['some value', [1, 2, 3, 4], 'an integer']
d1.values() # dict_values(['some value', [1, 2, 3, 4], 'an integer'])

字典的值可以是任意Python对象,而键通常是不可变的标量类型(整数、浮点型、字符串)或元组(元组中的对象必须是不可变的) 。这被称为"可哈希性"。可以用hash函数检测一个对象是否是可哈希的(可被用作字典的键)。

python 复制代码
In [127]: hash('string')
Out[127]: 5023931463650008331
In [128]: hash((1, 2, (2, 3)))
Out[128]: 1097636502276347782
In [129]: hash((1, 2, [2, 3])) # fails because lists are mutable
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-129-800cd14ba8be> in <module>()
----> 1 hash((1, 2, [2, 3])) # fails because lists are mutable
TypeError: unhashable type: 'list'
3.1.8 集合

集合是无序的不可重复的元素的集合。你可以把它当做字典,但是只有键没有值所以集合(set)里的元素必须是可哈希的,因为集合本质上是一个哈希表结构。哈希表要求元素的哈希值固定,以便能够快速判断元素的唯一性和执行查找操作。所以,像数字、字符串、元组(里面不包含可变对象)等可哈希的类型可以作为集合的元素,而列表、字典等不可哈希的类型不能直接放入集合中。

diff 复制代码
In [127]: {[1,2,3]}
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-173-f70e4b6b8fd1> in <module>()
----> 1 {[1,2,3]}

TypeError: unhashable type: 'list'
In [128]: set([1,2,3,2,1])
Out[128]: {1, 2, 3} #上面是把列表放到集合里,所以报错;下面是把列表转换为集合,不报错。
In [129]: ([1,2,3])
Out[128]: (1, 2, 3) #这里把列表转化成元组,就不会报错;没有集合的要求(集合里面的元素必须可哈希)
3.1.9 列表推导式

列表推导式是Python最受喜爱的特性之一。它允许用户方便的从一个集合过滤元素,形成列表,在传递参数的过程中还可以修改元素。map函数可以进一步简化,形式如下:

diff 复制代码
#列表推导式 [expr for val in collection if condition]
In [154]: strings = ['a', 'as', 'bat', 'car', 'dove', 'python']
In [155]: [x.upper() for x in strings if len(x) > 2]
Out[155]: ['BAT', 'CAR', 'DOVE', 'PYTHON']
# map函数可以进一步简化
In [158]: set(map(len, strings))
Out[158]: {1, 2, 3, 4, 6}
#字典推导式 dict_comp = {key-expr : value-expr for value in collection if condition}
In [159]: loc_mapping = {val : index for index, val in enumerate(strings)}
In [160]: loc_mapping
Out[160]: {'a': 0, 'as': 1, 'bat': 2, 'car': 3, 'dove': 4, 'python': 5}

嵌套列表推导式

diff 复制代码
In [164]: some_tuples = [(1, 2, 3), (4, 5, 6), (7, 8, 9)]
In [165]: flattened = [x for tup in some_tuples for x in tup]
In [166]: flattened
Out[166]: [1, 2, 3, 4, 5, 6, 7, 8, 9]
In [167]: [[x for x in tup] for tup in some_tuples]
Out[167]: [[1, 2, 3], [4, 5, 6], [7, 8, 9]]

3.2 函数

3.2.1 global关键字

global关键字声明全局变量。

diff 复制代码
In [168]: a = None
In [169]: def bind_a_variable():
   .....:     global a
   .....:     a = []
   .....: bind_a_variable()
   .....:
In [170]: print(a)
[]
3.2.2 return的不同表现

在Jupyter Notebook和PyCharm中,return语句的行为在交互式模式和脚本模式下表现有所不同。

(1) Jupyter Notebook

  • 在Jupyter中,最后一个表达式的值会被自动打印出来,因此如果在单元格中调用一个返回值的函数,Jupyter会直接显示结果。
  • 例如,如果你在一个单元格中写了 my_function(),并且 my_function 有返回值,那么该返回值会被自动显示出来。
  • 这让Jupyter非常适合交互式数据分析,因为你可以快速看到每个步骤的输出。

(2) PyCharm

  • PyCharm采用的是脚本模式 ,不会自动打印return的结果,除非显式调用print()函数。
  • 当执行代码时,Python解释器只是运行整个脚本,而不会自动显示任何返回值,除非用 print() 命令来显示返回值。
  • 所以在PyCharm中,如果你希望看到某个函数的返回结果,应该使用 print(my_function())
python 复制代码
def add(a, b):
    return a + b
# jupyter notebook
add(2, 3)  # 在Jupyter中直接写这行代码会显示结果 5

# pycharm
add(2, 3)  # 运行代码不会显示结果
print(add(2, 3))  # 使用print()才能看到输出 5
3.2.3 lambda匿名函数

Python支持一种被称为匿名的、或lambda函数。lambda函数之所以会被称为匿名函数,与def声明的函数不同,原因之一就是这种函数对象本身是没有提供名称name属性。

python 复制代码
# lambda匿名函数当作变量(对象)作为函数参数
def apply_to_list(some_list, f):
    return [f(x) for x in some_list]
ints = [4, 0, 1, 5, 6]
apply_to_list(ints, lambda x: x * 2)

# lambda匿名函数作为sort函数的key值选取。
In [177]: strings = ['foo', 'card', 'bar', 'aaaa', 'abab']
In [178]: strings.sort(key=lambda x: len(set(list(x))))
In [179]: strings
Out[179]: ['aaaa', 'foo', 'abab', 'bar', 'card']
3.2.4 柯里化:部分参数应用
python 复制代码
def add_numbers(x, y):
    return x + y
add_five = lambda y: add_numbers(5, y)
add_five(6) # 输出11(5+6=11)
3.2.5 可迭代对象

在Python中,可迭代对象是指可以逐一访问其元素的对象,常见的有列表、元组、字符串、字典、集合等容器类型,以及生成器和 range 对象等。只要对象实现了 __iter__() 方法或 __getitem__() 方法,就可以用 for 循环进行遍历,称为可迭代对象

能以一种一致的方式对序列进行迭代(比如列表中的对象或文件中的行)是Python的一个重要特点。这是通过一种叫做迭代器协议(iterator protocol,它是一种使对象可迭代的通用方式)的方式实现的,一个原生的使对象可迭代的方法。比如说,对字典进行迭代可以得到其所有的键:

python 复制代码
In [180]: some_dict = {'a': 1, 'b': 2, 'c': 3}
In [181]: for key in some_dict:
   .....:     print(key)
a
b
c
In [182]: dict_iterator = iter(some_dict)
In [183]: dict_iterator
Out[183]: <dict_keyiterator at 0x7fbbd5a9f908>

# 迭代器是一种特殊对象,它可以在诸如for循环之类的上下文中向Python解释器输送对象。
# 大部分能接受列表之类的对象的方法也都可以接受任何可迭代对象。
# 比如min、max、sum等内置方法以及list、tuple等类型构造器。
In [184]: list(dict_iterator)
Out[184]: ['a', 'b', 'c']
3.2.6 生成器相关

**生成器(generator)**是构造新的可迭代对象的一种简单方式。一般的函数执行之后只会返回单个值,而生成器则是以延迟的方式返回一个值序列,即每返回一个值之后暂停,直到下一个值被请求时再继续。要创建一个生成器,只需将函数中的return替换为yeild即可:

python 复制代码
def squares(n=10):
    print('Generating squares from 1 to {0}'.format(n ** 2))
    for i in range(1, n + 1):
        yield i ** 2
In [186]: gen = squares()
In [187]: gen
Out[187]: <generator object squares at 0x7fbbd5ab4570>

直到你从该生成器中请求元素时,它才会开始执行其代码:

python 复制代码
In [188]: for x in gen:
   .....:     print(x, end=' ')
Generating squares from 1 to 100
1 4 9 16 25 36 49 64 81 100

另一种更简洁的构造生成器的方法是使用生成器表达式 (generator expression)。这是一种类似于列表、字典、集合推导式的生成器。其创建方式为,把列表推导式两端的方括号改成圆括号

python 复制代码
In [189]: gen = (x ** 2 for x in range(100))
In [190]: gen
Out[190]: <generator object <genexpr> at 0x7fbbd5ab29e8>
In [191]: sum(x ** 2 for x in range(100)) #生成器表达式也可以取代列表推导式,作为函数参数
Out[191]: 328350
In [192]: sum([x ** 2 for x in range(100)])
Out[192]: 328350
In [193]: ((i, i **2) for i in range(5))
Out[193]: <generator object <genexpr> at 0x000001BBCD199A20>

标准库itertools模块中有一组用于许多常见数据算法的生成器。例如,groupby可以接受任何序列和一个函数。它根据函数的返回值对序列中的连续元素进行分组。(类似于mysql的groupby)下面是一个例子:

python 复制代码
In [193]: import itertools
In [194]: first_letter = lambda x: x[0]
In [195]: names = ['Alan', 'Adam', 'Wes', 'Will', 'Albert', 'Steven']
# lamdba函数作为groupby的参数
In [196]: for letter, names in itertools.groupby(names, first_letter):
   .....:     print(letter, list(names)) # names is a generator
A ['Alan', 'Adam']
W ['Wes', 'Will']
A ['Albert']
S ['Steven']
3.2.7 map函数用法

map(function, iterable),举个例子,值得注意的是,map 返回的是一个迭代器,我们可以将它转换为列表以便查看结果。

python 复制代码
# 定义一个函数,用于返回数字的平方
def square(x):
    return x ** 2

# 创建一个包含数字的列表
numbers = [1, 2, 3, 4, 5]

# 使用 map 函数,将 square 函数应用到每个数字上
squared_numbers = map(square, numbers)

# map 返回的是一个迭代器,我们可以将它转换为列表以便查看结果
print(list(squared_numbers))

下面举例中,函数用的是lambda匿名函数。

python 复制代码
In [189]: map(lambda x: x * 2, [1, 2, 3, 4, 5])
Out[189]: <map at 0x18550f02be0>
In [190]: list(map(lambda x: x * 2, [1, 2, 3, 4, 5]))
Out[190]: [2, 4, 6, 8, 10]
3.2.8 try-except-else-finally结构
python 复制代码
f = open(path, 'w')
try:
    write_to_file(f)
except: #try失败了才执行
    print('Failed') 
else: #try成功了才执行
    print('Succeeded') 
finally: #不管try成功与否都执行
    f.close() 

3.3 文件的打开与关闭

python 复制代码
In [207]: path = 'examples/segismundo.txt'
In [208]: f = open(path)
In [211]: f.close()
模式 说明
r 只读模式
w 只写模式。创建新文件(删除同名的任何文件【译注12】)
a 附加到现有文件(如果文件不存在则创建一个)
r+ 读写模式
b 附加说明某模式用于二进制文件,即rbwb
U 通用换行模式。单独使用'U'或附加到其他读模式(如rU

用with语句可以可以更容易地清理打开的文件:

python 复制代码
In [212]: with open(path) as f:
   .....:     lines = [x.rstrip() for x in f]

这样可以在退出代码块时,自动关闭文件。

read() 读取整个文件为字符串,readlines() 逐行读取文件并返回一个列表。

write() 用于将字符串写入文件,而 writelines() 则用于将多个行(如列表或元组中的元素)一次性写入文件。注意,write()writelines() 都不会自动添加换行符,需要手动添加。

这里的行指的是换行符,可以是手动输入的"/n",更多指的是按enter在文本文件形成的换行符。

python 复制代码
# 要写入的多行文本,每行末尾手动加上换行符
lines_to_write = [
    'This is the first line.\n',
    'This is the second line.\n',
    'This is the third line.\n'
]

# 打开文件,写入模式 'w' 表示如果文件存在会覆盖,如果不存在则创建
with open('example.txt', 'w') as file:
    file.writelines(lines_to_write)

print("写入完成!")

最后加一点第二章的知识。

3.4 其他

.py文件的执行

在pycharm和jupyter里运行某个.py文件的不同方法。

python 复制代码
# 文件是C:\Users\13642\PycharmProjects\pythonProject\pycharmproject\666\draft.py
def a():
    return 1
a() # 用于对比jupyter和pycharm对return的处理方式
print(a())

在终端执行用python关键字。(cmd进的终端或pycharm里的都可以)

python 复制代码
C:\Users\13642>python C:\Users\13642\PycharmProjects\pythonProject\pycharmproject\666\draft.py
1

魔术命令是 Jupyter Notebook 中的特有功能,它们提供了增强 Jupyter 功能的快捷方式,魔术命令(Magic Commands)并不完全等同于 Linux 命令加上 %,但它们有一些相似的作用和用途。

在jupyter notebook执行用%run魔法命令。(%run 命令只能在 Jupyter Notebook 或 IPython 环境中使用)

python 复制代码
In [207]: %run C:\Users\13642\PycharmProjects\pythonProject\pycharmproject\666\draft.py
Out[207]: 1

在 PyCharm 的 Python Console 中,可以使用**exec()**来执行 Python 文件,或者使用 PyCharm 内置的运行功能。

python 复制代码
exec(open(r'C:\Users\13642\PycharmProjects\pythonProject\pycharmproject\666\draft.py').read())
1

PyCharm ConsoleJupyter Notebook 确实有一些相似的地方,它们都提供了交互式编程 的体验,允许用户实时输入代码、执行代码并查看结果。,但差异也有很多(比如**%run** 命令和**exec()**函数执行.py文件)

jupyter最后一行代码返回值

tip:这里为什么jupyter执行的draft.py没有返回两个1?

-----------------------------------------------应该比较重要-----------------------------------------------------------

在 Jupyter Notebook 中,每个单元格只会自动显示最后一行代码的返回值 。虽然你在中间调用了 a(),但它不是最后一行,所以 Jupyter 不会自动显示它的返回值。

----------------------------------------------------------------------------------------------------------------------------

上面提到的return相关:

python 复制代码
def add(a, b):
    return a + b
# jupyter notebook
add(2, 3)  # 在Jupyter中直接写这行代码会显示结果 5

# pycharm
add(2, 3)  # 运行代码不会显示结果
print(add(2, 3))  # 使用print()才能看到输出 5

接着进一步尝试,发现返回的两个"1"亦有区别:

首先是print(a())放在a()之前,我们会发现,print出来的1不在out输出里面,而在in输入方框下面,out输出的1是由于a()return的。

然后是a()放在print(a())之前,由于a()不是最后一行代码,所以out没有输出,只有print(a())的输出。

isinstance、isiterable

isinstance判断类型,isiterable判断是否可迭代。

python 复制代码
In [21]: a = 5
In [22]: isinstance(a, int)
Out[22]: True
In [23]: a = 5; b = 4.5
In [24]: isinstance(a, (int, float))
Out[24]: True
In [25]: isinstance(b, (int, float))
Out[25]: True
In [29]: isiterable('a string')
Out[29]: True
In [30]: isiterable([1, 2, 3])
Out[30]: True
字符串的replace()方法

Python的字符串是不可变的,不能修改字符串。可以用replace()方法把一个字符串里部分字符替换成其他字符,并赋值给新变量,但原本的字符串不会变化。

python 复制代码
In [58]: b = a.replace('string', 'longer string')
In [59]: b
Out[59]: 'this is a longer string'
datetime模块

Python内建的datetime模块提供了datetimedatetime类型。datetime类型结合了datetime,是最常使用的:

python 复制代码
In [102]: from datetime import datetime, date, time
In [103]: dt = datetime(2011, 10, 29, 20, 30, 21)
In [104]: dt.day
Out[104]: 29
In [105]: dt.minute
Out[105]: 30
In [106]: dt.date()
Out[106]: datetime.date(2011, 10, 29)
In [107]: dt.time()
Out[107]: datetime.time(20, 30, 21)

# strftime方法可以将datetime格式化为字符串。
In [108]: dt.strftime('%m/%d/%Y %H:%M')
Out[108]: '10/29/2011 20:30'
# strptime可以将字符串转换成datetime对象。
In [109]: datetime.strptime('20091031', '%Y%m%d')
Out[109]: datetime.datetime(2009, 10, 31, 0, 0)

In [110]: dt.replace(minute=0, second=0)
Out[110]: datetime.datetime(2011, 10, 29, 20, 0)
In [111]: dt2 = datetime(2011, 11, 15, 22, 30)
In [112]: delta = dt2 - dt
In [113]: delta
# 结果timedelta(17, 7179)指明了timedelta将17天、7179秒的编码方式.
Out[113]: datetime.timedelta(17, 7179) 

In [114]: type(delta)
Out[114]: datetime.timedelta
In [115]: dt
Out[115]: datetime.datetime(2011, 10, 29, 20, 30, 21)
In [116]: dt + delta
Out[116]: datetime.datetime(2011, 11, 15, 22, 30)
三元表达式
python 复制代码
value = true-expr if condition else false-expr
In [126]: x = 5
In [127]: 'Non-negative' if x >= 0 else 'Negative'
Out[127]: 'Non-negative'
相关推荐
Alive~o.08 分钟前
Go语言进阶&依赖管理
开发语言·后端·golang
花海少爷11 分钟前
第十章 JavaScript的应用课后习题
开发语言·javascript·ecmascript
手握风云-11 分钟前
数据结构(Java版)第二期:包装类和泛型
java·开发语言·数据结构
喵叔哟31 分钟前
重构代码中引入外部方法和引入本地扩展的区别
java·开发语言·重构
尘浮生37 分钟前
Java项目实战II基于微信小程序的电影院买票选座系统(开发文档+数据库+源码)
java·开发语言·数据库·微信小程序·小程序·maven·intellij-idea
hopetomorrow1 小时前
学习路之PHP--使用GROUP BY 发生错误 SELECT list is not in GROUP BY clause .......... 解决
开发语言·学习·php
SelectDB技术团队1 小时前
兼顾高性能与低成本,浅析 Apache Doris 异步物化视图原理及典型场景
大数据·数据库·数据仓库·数据分析·doris
小牛itbull1 小时前
ReactPress vs VuePress vs WordPress
开发语言·javascript·reactpress
请叫我欧皇i1 小时前
html本地离线引入vant和vue2(详细步骤)
开发语言·前端·javascript
nuclear20111 小时前
使用Python 在Excel中创建和取消数据分组 - 详解
python·excel数据分组·创建excel分组·excel分类汇总·excel嵌套分组·excel大纲级别·取消excel分组