用Python进行数据分析 第三章 内建数据结构,函数及文件

3.1.1 Tuple

  • 不可变
  • 用逗号分隔

最常用的方法就是

In [6]: tup=4,5,6
In [7]: tup
Out[7]: (4, 5, 6)

稍微复杂点的情况可以用括号隔开

In [8]: nested_tup=(4,5,6),(7,8)
In [9]: nested_tup
Out[9]: ((4, 5, 6), (7, 8))

序列和字符也可以转换成tuple

In [10]: tuple([4,0,2])
Out[10]: (4, 0, 2)
In [11]: tuple("strings")
Out[11]: ('s', 't', 'r', 'i', 'n', 'g', 's')

数据被设置成tuple以后就没法改变了,

In [18]: tup=tuple(["foo",[1,2],True])

In [19]: tup[2]=False
Traceback (most recent call last):

  File "<ipython-input-19-e84077ea19c6>", line 1, in <module>
    tup[2]=False

TypeError: 'tuple' object does not support item assignment

但是可以在其中部分成分水平上就行改变,比方说

In [20]: tup[1].append(3)

In [21]: tup
Out[21]: ('foo', [1, 2, 3], True)

也可以用+来连接两个tuple

In [22]: (4,None,"foo")+(6,0)+("bar",)
Out[22]: (4, None, 'foo', 6, 0, 'bar')

也可以用乘号

("foo","bar")*4
Out[23]: ('foo', 'bar', 'foo', 'bar', 'foo', 'bar', 'foo', 'bar')

3.1.1.1 tuple的分解

先定义一个tuple,然后分成a,b,c三个成分

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

In [25]: a,b,c=tup

In [26]: b
Out[26]: 5

In [27]: a
Out[27]: 4

In [28]: c
Out[28]: 6

也可以用来交换变量名,像下面那样a,b对换

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

In [30]: a
Out[30]: 2

In [31]: b
Out[31]: 1

In [32]: b,a=a,b

In [33]: a
Out[33]: 1

In [34]: b
Out[34]: 2

分解的一般用途是用来对tuple或者list进行重复处理,比方说

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))
a=1,b=2,c=3
a=4,b=5,c=6
a=7,b=8,c=9

3.1.2 List

list有以下特点

  • 长度可变
  • 内容可变
In [1]: a_list=[2,3,4,None]

In [2]: tup=("foo","bar","baz")

In [3]: b_list=list(tup)

In [4]: b_list
Out[4]: ['foo', 'bar', 'baz']

In [5]: b_list[1]="peekaboo"

In [6]: b_list
Out[6]: ['foo', 'peekaboo', 'baz']

3.1.2.1 追加和删除要素

使用append

In [7]: b_list.append("dwarf")

In [8]: b_list
Out[8]: ['foo', 'peekaboo', 'baz', 'dwarf']

也可以在指定位置插入指定内容

In [9]: b_list.insert(1,"red")

In [10]: b_list
Out[10]: ['foo', 'red', 'peekaboo', 'baz', 'dwarf']

删除用remove

In [14]: b_list.append("foo")
    ...: b_list
Out[14]: ['foo', 'red', 'dwarf', 'foo', 'foo']

In [15]: b_list.append("foo")
    ...: b_list
    ...: b_list.remove("foo")
Out[16]: ['red', 'dwarf', 'foo', 'foo', 'foo']

3.1.2.2 连接list

list的叠加也可以通过+来完成

In [18]: [4,None,"foo"]+[7,8,(2,3)]
Out[18]: [4, None, 'foo', 7, 8, (2, 3)]

或者extend,extend要比普通函数来的快速

In [21]: x=[4,None,"foo"]

In [22]: x.extend([7,8,(2,3)])

In [23]: x
Out[23]: [4, None, 'foo', 7, 8, (2, 3)]

3.1.2.3 sort

用来排序

In [28]: a=[7,2,5,1,4]

In [29]: a.sort()

In [30]: a
Out[30]: [1, 2, 4, 5, 7]

3.1.2.3 sort

sort用来排序

In [22]: a=[7,2,5,1,3]

In [23]: a.sort()

In [24]: a
Out[24]: [1, 2, 3, 5, 7]

sort这个函数也有option,比方说key=len,根据长度排序

In [26]: b=["saw","small","He","foxes","six"]

In [27]: b.sort(key=len)

In [28]: b
Out[28]: ['He', 'saw', 'six', 'small', 'foxes']

3.1.2.5 Slicing

这个概念比较搞,特别是对于经历过R和MATLAB的人

In [29]: seq=[7,2,3,7,5,6,0,1]

In [30]: seq[1:5]
Out[30]: [2, 3, 7, 5]

正如上图所示,索引值被安排在了箱体边缘。既可以正过来选择,也可以用负数进行逆向选择。

In [34]: seq[3:4]=[6,3]

In [35]: seq
Out[35]: [7, 2, 3, 6, 3, 5, 6, 0, 1]

::表示隔开,下面的例子就是每隔两个边缘,也就是一个项目,提取字母。

seq[::2]
Out[37]: [7, 3, 3, 6, 1]

反转列表

seq[::-1]
Out[36]: [1, 0, 6, 5, 3, 6, 3, 2, 7]

3.1.3 序列函数

3.1.3.1 enumerate

我们在对一个序列的数据进行逐次处理的时候一般需要保持这个序列的索引值,比方说

i=0
for value in collection: 
# 使用value做点事
i += 1

其实python内置了这样的函数enumerate, 返回了(i, value)元组的序列,其中value是元素的值,i 是元素的索引。

for i, value in enumerate(collection):

当你需要对数据建立索引时,一种有效的模式就是使用enumerate建立字典。对每一个value(v)建立相对应的索引 i 。

In [49]: some_list=['foo','bar','baz']
    ...: mapping={}
    ...: for i, v in enumerate(some_list):
    ...:     mapping[v]=i
    ...: mapping
Out[49]: {'foo': 0, 'bar': 1, 'baz': 2}

3.1.3.2 sorted

把序列进行排序并产生新的序列

In [50]: sorted([7,1,2,6,0,3,2])
Out[50]: [0, 1, 2, 2, 3, 6, 7]

3.1.3.3 zip

zip函数可以把多个list, tuple以及其他序列配对,组合成一个数据。
zip可以处理任意长度的序列,它生成的列表长度由最短的序列决定。

In [51]: seq1=['foo','bar','baz']

In [52]: seq2=['one','two','three']

In [53]: zipped=zip(seq1,seq2)
In [55]: list(zipped)
Out[55]: [('foo', 'one'), ('bar', 'two'), ('baz', 'three')]

zip也可以和enumerate同时使用

In [61]: for i,(a,b) in enumerate(zip(seq1,seq2)):
    ...:     print('{0}:{1},{2}'.format(i,a,b))
0:foo,one
1:bar,two
2:baz,three

对于一个已经配对的序列时,zip还可以对其进行拆分。这个语法非常匪夷所思,除了死记硬背也没有别的方法。

In [62]: pitchers=[('Nolan','Ryan'),('Roger','Clemens'),('Schilling','Curt')]

In [63]: first_names,last_names=zip(*pitchers)

In [64]: first_names
Out[64]: ('Nolan', 'Roger', 'Schilling')
In [65]: last_names
Out[65]: ('Ryan', 'Clemens', 'Curt')

3.1.4 字典

dict(字典)可能是python内建数据结构中最重要的。字典拥有灵活尺寸的键值对合集。key and value。用大括号{}是创建字典的一种方式,在字典中用逗号将key and value分隔。

empty_dict={}
In [67]: d1={'a': 'some value', 'b': [1,2,3,4]}

In [68]: d1
Out[68]: {'a': 'some value', 'b': [1, 2, 3, 4]}

可以通过key来查阅对应的value

In [70]: d1['b']
Out[70]: [1, 2, 3, 4]

也可以进行简单的逻辑判断

In [71]: 'b' in d1
Out[71]: True

也可以添加key和value组

In [72]: d1[7]='an interger'
In [73]: d1
Out[73]: {'a': 'some value', 'b': [1, 2, 3, 4], 7: 'an interger'}

也可以用del或者pop来删除值,不一样的是pop在删除的同时会返回被删的值,可以保存,相当于抠出来

In [72]: d1[7]='an interger'

In [73]: d1
Out[73]: {'a': 'some value', 'b': [1, 2, 3, 4], 7: 'an interger'}

In [74]: d1[5]='what if'

In [75]: d1
Out[75]: {'a': 'some value', 'b': [1, 2, 3, 4], 7: 'an interger', 5: 'what if'}

In [76]: d1['dummy']='another value'

In [77]: del d1[5]

In [78]: d1
Out[78]: 
{'a': 'some value',
 'b': [1, 2, 3, 4],
 7: 'an interger',
 'dummy': 'another value'}
In [79]: ret=d1.pop('dummy')

In [80]: ret
Out[80]: 'another value'
In [81]: d1
Out[81]: {'a': 'some value', 'b': [1, 2, 3, 4], 7: 'an interger'}

可以用update将两个字典进行合并

In [82]: d1.update({'b':'foo','c':12})

In [83]: d1
Out[83]: {'a': 'some value', 'b': 'foo', 7: 'an interger', 'c': 12}

值得注意的是如果key值和之前的字典里的相同时,将会被覆盖。

3.1.4.1 从序列生成字典

一般情况下,如果有想要把两个序列匹配成字典,会有以下的想法,

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

由于字典的本质是含有2个元素的元组的集合,所以字典会允许接受一个2元元组的列表作为参数。

In [84]: mapping =dict(zip(range(5),reversed(range(5))))

In [85]: mapping
Out[85]: {0: 4, 1: 3, 2: 2, 3: 1, 4: 0}

3.1.4.2 默认值

我们可以用if-esle给特定的key的value赋值,

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

除此以外,还可以用get来,

value = some_dict.get(key, default_value)

文中还介绍了setdefault,说实话没有看懂,暂时跳过。

3.1.4.3 有效的字典键类型

跳过

3.1.5 集合

集合是一种无序且元素唯一的容器,可以通过set函数或者字母值集与大括号的语法来建立

In [6]: set([2,2,2,1,3,3])
Out[6]: {1, 2, 3}
In [7]: {2,2,2,1,3,3}
Out[7]: {1, 2, 3}

支持数学上的集合操作,比方说取合集

In [8]: a={1,2,3,4,5}
In [9]: b={3,4,5,6,7,8}

In [10]: a.union(b)
Out[10]: {1, 2, 3, 4, 5, 6, 7, 8}

In [11]: a|b
Out[11]: {1, 2, 3, 4, 5, 6, 7, 8}

或者取交集

In [12]: a.intersection(b)
Out[12]: {3, 4, 5}
In [13]: a&b
Out[13]: {3, 4, 5}

值得一提的是,合集里面的元素和字典类似,都是不可变的,如果想要包含列表型的元素,必须先转换为元组。

3.1.6 列表,集合和字典的推导式

列表推导式是最受欢迎的Python语言特性之一。它可以允许过滤一个容器的元素,用一种简明的表达式转换传递给过滤器的元素,从而形成一个新的列表。基本形式为:
[expr for val in collection if condition],
这个相当于以下的for循环

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

例如给定一个字符串列表,我们可以通过过滤出长度大于2的字符串,并且将其改写成大写。

In [1]: strings=['a','as','bat','car','dove','python']

In [2]: [x.upper() for x in strings if len(x)>2]
Out[2]: ['BAT', 'CAR', 'DOVE', 'PYTHON']

字典和集合也是大同小异

  • 字典
    dict_comp={key-expr : value-expr for value in collection if condition}
  • 集合
    和列表差不多,只不过是中括号变成了大括号
    set_comp={expr for value in collection if condition}

假设我们想要得到一个集合,集合里包含了刚才列表中字符串的长度

In [3]: unique_lengths={len(x) for x in strings}

In [4]: unique_lengths
Out[4]: {1, 2, 3, 4, 6}

这个函数等价于

In [5]: set(map(len,strings))
Out[5]: {1, 2, 3, 4, 6}

接下来举个字典的例子

In [6]: loc_mapping={val: index for index, val in enumerate(strings)}
In [7]: loc_mapping
Out[7]: {'a': 0, 'as': 1, 'bat': 2, 'car': 3, 'dove': 4, 'python': 5}

3.2.3 函数是对象

假设我们在做数据清洗,需要把一些变形运用到如下的字符串列表中,

In [2]: states=[' Alabama','Georgia!','Georgia!','georgia','Fl0rIda',
   ...:         'south carolina##', 'West virginia?']

我们需要对这些数据进行如下操作,去除空格,移除标点符号,调整大小写。一种方式是可以调用内建的字符串方法,结合标准库中的正则表达re

IPdb [18]: def clean_strings(strings):
      ...:     result=[]
      ...:     for value in strings:
      ...:         value = value.strip()
      ...:         value = re.sub('[!#?]','',value)
      ...:         value = value.title()
      ...:         result.append(value)
      ...:     return result

IPdb [19]: clean_strings(states)
['Alabama', 'Georgia', 'Georgia', 'Georgia', 'Fl0Rida', 'South Carolina', 'West Virginia']

虽然并不是能完全理解python的正则表达,但大概可以看懂这是写了一个函数,分别进行了三步处理。
还有一个方法就是在函数里套用函数,

# 自定义一个小函数
IPdb [20]: def remove_puncatuation(value):
      ...:     return re.sub('[!#?]','',value)
# 把几个小函数合并成一个函数列表
IPdb [21]: clean_ops = [str.strip,remove_puncatuation,str.title]
# 字符和函数都用for循环连续处理起来
IPdb [22]: def clean_strings(strings,ops):
      ...:     result = []
      ...:     for value in strings:
      ...:         for function in ops:
      ...:             value = function(value)
      ...:         result.append(value)
      ...:     return result


IPdb [24]: clean_strings(states,clean_ops)
['Alabama', 'Georgia', 'Georgia', 'Georgia', 'Fl0Rida', 'South Carolina', 'West Virginia']

函数是python里最重要,最基础的代码组织和代码复用的方式。比方说如果你要多次重复相同或类似的代码,就可以写一个可复用的函数。

def my_function(x,y,z=1.5):
    if z > 1:
        return z*(x+y)
    else:
        return z/(x+y)

3.2.1 命名空间,作用域和本地函数

函数有两种连接变量的方式:全局,本地。在Python中另外一个更加贴切的描述变量作用域的名称是命名空间。在函数内部,任意变量都会默认分配到本地命名空间。本地命名空间实在函数被调用时生成的,并立即由函数的参数填充。当函数执行结束以后,本地命名空间就会被销毁。

def func():
    a = []
    for i in range(5):
        a.append(i)

当调用func()时,空的列表a会被建立,五个元素被添加到列表以后,a会在函数推出时销毁。

3.2.2 返回多个值

使用简单语法就可以从函数中返回多个值,如下

def f():
    a=5
    b=6
    c=7
    return a,b,c

a,b,c=f()

在数据分析和其他科研应用中,经常需要返回多个值,这里实质上是返回一个对象,也就是元组,而元组之后又被拆分为多个结果变量。刚才的例子也可以被以下的代码替换

return_value = f()

在这个例子中,return_value是一个包含3个元素的元组,像之前那样一次返回多个值还可以返回成字典模式

def f():
    a=5
    b=6
    c=7
    return{'a':a,'b':b,'c':c}

其实就是取决于你想做什么。

Lambda函数

210705
Python支持所谓的匿名lambda函数。lambda函数是一种通过单个语句生成函数的方式,其结果是返回值。匿名函数使用lambda关键字定义,该关键字表达在此声明一个函数。

def short_function(x):
    return x*2
equiv_anon = lambda x: x*2

因为lambda函数简短易懂,所以会经常被使用。再举个例子,先定一个自定义函数,然后用lambda函数执行。

In [10]: 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)
Out[10]: [8, 0, 2, 10, 12]

另外再举一个例子,将lambda函数出给列表中的sort的方法:

In [15]: strings=['foo','card','bar','aaaa','abab']
In [16]: strings.sort(key=lambda x: len(set(list(x))))
In [17]: strings
Out[17]: ['aaaa', 'foo', 'abab', 'bar', 'card']

3.2.5 柯里化: 部分参数应用

用已有的函数衍生出新的函数。

def add_mumbers(x,y):
    return x+y

使用这个函数,就衍生出了一个只有一个变量的新函数,add_five,可以给参数加上5

def add_mumbers(x,y):
    return x+y
add_five = lambda y: add_numbers(5,y)

怎么样,是不是都连起来了。虽然也没有什么神奇的地方。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,324评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,356评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,328评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,147评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,160评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,115评论 1 296
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,025评论 3 417
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,867评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,307评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,528评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,688评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,409评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,001评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,657评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,811评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,685评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,573评论 2 353

推荐阅读更多精彩内容