Python数据分析的第一步是了解Python的数据结构及对应的数据常规操作。
- 数据基本结构包括元组(tuple)、列表(list)、字典(dictionary)、集合(set),是构成各类数据的基本要件;
- 存储数据的常见形式包括ndarray、Series、DataFrame,是存储大型数据信息的主要形式,可由元组、列表、字典、集合转换而成;
- 数据常规操作包括数据属性(方法)、数据创建、数据切片(索引)、数据修改、数据排序、数据转换、数据计算,是进行数据分析的基础操作。
本节主要讲述数据基本结构及其常规操作。
目录
一、元组(tuple)
1.1 元组创建
tup1=(1,2,3) # 通过括号创建
tup2=4,5,6 # 直接通过逗号创建
tup3=tuple([4,5,6]) # 将其它数据格式转换为元组
print ('tup1:',tup1,'\n','tup2:',tup2,'\n','tup3:',tup3)
输出结果为:
tup1: (1, 2, 3)
tup2: (4, 5, 6)
tup3: (4, 5, 6)
1.2 元组属性
元组是长度、顺序和元素均不可变的python序列。
tup1[4]=6
输出结果为:
TypeError Traceback (most recent call last)
<ipython-input-10-8966dcb4c8bc> in <module>()
----> 1 tup1[4]=6
TypeError: 'tuple' object does not support item assignment
1.3 元组切片
tup4=(1,(2,3),[4,5,6],'str')
tup4[1]
输出结果为:
(2, 3)
1.4 元组拆包
元组拆包是通过赋值的形式,将元组元素赋值给变量。
(1) 普通元组拆包
a,b,c,d=tup4
print(a,b,c,d)
输出结果为:
1 (2, 3) [4, 5, 6] str
(2)嵌套元组拆包
a,(b,c),d,e=tup4
b
输出结果为:
2
(3)高级元组拆包
a,*rest,b=tup4
print(a,b)
输出结果为:
1 str
1.5 元组计算
(1)通过加号运算实现拼接
tup1+tup4
输出结果为:
(1, 2, 3, 1, (2, 3), [4, 5, 6], 'str')
(2)通过与数字运算实现复制
tup1*2
输出结果为:
(1, 2, 3, 1, 2, 3)
1.6 元组方法
tuple.count 计算元组某个值出现的次数。
tup1.count(1)
输出结果为:
1
二、 列表(List)
2.1 列表创建
(1)通过[ ]创建
list1=[1,2,3,None]
list1
输出结果为:
[1, 2, 3, None]
(2)通过list创建
list2=list((1,2,3,None))
list2
输出结果为:
[1, 2, 3, None]
2.2 列表修改
2.2.1 增加元素
(1)在尾部增加元素
list1.append('str')
list1
输出结果为:
[1, 2, 3, None, 'str']
(2)在列表任意位置插入元素
help(list.insert)
list1.insert(1,'str')
list1
输出结果为:
[1, 'str', 2, 3, None, 'str']
2.2.2 删除元素
(1)在指定位置删除元素
list1.pop(1)
list1
输出结果为:
'str'
[1, 3, None, 'str']
(2)删除指定元素
list1.remove(3)
输出结果为:
[1,None,'str']
2.2.3 判断元素是否在列表中
判断元素是否在列表中 in/ not in
1 in list2
输出结果为:
True
1 not in list2
输出结果为:
False
2.3 列表拼接和联合
(1)通过加号运算实现list拼接
list2+[1,2]
输出结果为:
[1, 'str', 'str', 2, 3, None, 1, 2]
(2)通过extend实现拼接或者添加更多元素
extend相对加号运算更加高效,相对append方法可以添加多个元素
list2.extend([1,2])
输出结果为:
[1, 'str', 'str', 2, 3, None, 1, 2]
对应地:
list2.append([1,2])
输出结果为:
[1, 'str', 'str', 2, 3, None, [1,2]]
2.4 列表排序
利用list的sort方法进行排序。
help(list.sort)
Help on method_descriptor:
sort(self, /, *, key=None, reverse=False)
Stable sort *IN PLACE*.
list3=[1,2,3,4,5]
list3.sort()
list3
输出结果为:
[1, 2, 3, 4, 5]
list4=['a','bb','ccc','dddd']
list4.sort(key=len)
list4
输出结果为:
['a', 'bb', 'ccc', 'dddd']
2.5 二分搜索和已排序列表的维护
二分查找算法(英语:binary search algorithm),也称折半搜索算法(half-interval search algorithm)、对数搜索算法(logarithmic search algorithm),是一种在有序数组中查找某一特定元素的搜索算法。具体参见[二分查找(折半查找)算法](http://data.biancheng.net/view/122.html)
二分查找法的python实现:bisect模块
bisect.bisect 通过二分查找法,返回指定值在有序序列中的位置值;bisect.insort 通过二分查找法,将指定值插入到有序序列中。
[in]:
import bisect
c=[1,2,2,2,3,4,7]
bisect.bisect(c,2)
[out]:
4
[in]:
bisect.insort(c,8)
c
[out]:
[1, 2, 2, 2, 3, 4, 7, 8]
2.6 列表切片
(1)切片某个位置的元素
[in]:c[1]
[out]:2
(2)切片某个位置区间的元素
[in]:c[2:6]
[out]:[2, 2, 3, 4]
(3)隔步取数
[in]:c[::2]
[out]:[1, 2, 3, 7, 8]
(4)反向取数
[in]:c[::-1]
[out]:[8, 7, 4, 3, 2, 2, 2, 1]
2.7 列表内建函数
2.7.1 enumerate 函数
enumerate() 函数用于将一个可遍历的数据对象(如列表、元组或字符串)组合为一个索引序列。enumerate is useful for obtaining an indexed list:(0, seq[0]), (1, seq[1]), (2, seq[2]), ...
[in]:some_list=['miaomiao','is','a','smart','girl']
some_list_out=enumerate(some_list)
some_list_out
[out]:<enumerate at 0x1d15a354ee8>
通过转换为字典形式实现输出和应用:
[in]:mapping=dict(some_list_out)
mapping
[out]:{0: 'miaomiao', 1: 'is', 2: 'a', 3: 'smart', 4: 'girl'}
通过for循环输出变量值:
[in]:for i,value in enumerate(some_list):
print(i,value)
[out]:
0 miaomiao
1 is
2 a
3 smart
4 girl
2.7.2 sorted 函数
与list对应的sort方法不同,sorted为全局函数,返回一个新的值
[in]:sorted(c)
[out]:[1, 2, 2, 2, 3, 4, 7, 8, 8]
2.7.3 zip 函数
zip()是一个内建函数,它接受一系列可迭代的对象作为参数,将对象中对应的元素打包成一个个tuple(元组),然后返回由这些tuples组成的list
(1)压缩
[in]:seq1=['foo','bar','baz']
seq2=[1,2,3,4]
zipped=zip(seq1,seq2)
zipped
[out]:<zip at 0x1d15a325588>
[in]:list(zipped)
[out]:[('foo', 1), ('bar', 2), ('baz', 3)]
zip的常用场景为同时遍历多个序列,有时会和enumerate同时使用:
[in]:for i,(a,b) in enumerate(zip(seq1,seq2)):
print('{0}:{1},{2}'.format(i,a,b))
[out]:0:foo,1
1:bar,2
2:baz,3
(2)解压
[in]:zipped1=[(1,'a'),(2,'b'),(3,'c')]
seq1,seq2=zip(*zipped1) # *为前缀运算符
print(seq1,seq2)
[out]:(1, 2, 3) ('a', 'b', 'c')
2.7.4 reversed 函数
reversed为倒序函数。
[in]:reversed(c)
[out]:<list_reverseiterator at 0x1d15a363898>
[in]:list(reversed(c))
[out]:[8, 7, 4, 3, 2, 2, 2, 1]
三、字典(Dictionary)
字典为键值对组合。
3.1 字典创建
(1) 用{}创建
[in]:d1={'a':'some value','b':[1,2,3]}
d1
[out]:{'a': 'some value', 'b': [1, 2, 3]}
(2)用dict函数生成
[in]:dict(zip(range(5),reversed(range(5))))
[out]:{0: 4, 1: 3, 2: 2, 3: 1, 4: 0}
3.2 字典切片
(1) 通过'key'切片
[in]:d1['a']
[out]:'some value'
(2)输出key
[in]:d1.keys()
[out]:dict_keys(['a', 'b'])
(3)输出values
[in]:d1.values()
[out]:dict_values(['some value', [1, 2, 3]])
3.3 字典修改
3.3.1 增加元素
通过赋值实现增加元素。
[in]:d1['c']=(4,5)
d1
[out]:{'a': 'some value', 'b': [1, 2, 3], 'c': (4, 5)}
3.3.2 删除元素
[in]:d1.pop('c')
[out]:(4, 5)
[in]:d1
[out]:{'a': 'some value', 'b': [1, 2, 3]}
3.3.3 判断元素是否在字典中
用in/ not in 检查字典中是否含某个键。
[in]:'some value' in d1
[out]:False
[in]:'a'in d1
[out]:True
3.4 字典合并
用update进行字典合并,如键值相同,则新值覆盖旧值:
[in]:d2={'a':1,'c':(4,5)}
d1.update(d2)
d1
[out]:{'a': 1, 'b': [1, 2, 3], 'c': (4, 5)}
3.5 设置默认值
为什么要设置字典默认值?dict作为常见的输出形式,经常出现以下的需求,即:假设输出的字典为dict,若调用的key在dict中,则返回dict[key],若key不在字典中,则返回一个设置的默认值default。
以上诉求经常需要一个if语句实现,即:
if key in dict:
value=dict[key]
else:
value=default
* 以上诉求可以通过dict.get(key,default=None)方法实现
[in]:d2={'a': 1, 'c': (4, 5), 'b': 0}
d2.get('a',0) # a在d2中,即返回d2['a']=1
[out]:1
[in]:d2.get('d',0) # d不在d2中,即返回设置的默认值0
[out]:0
[in]:d2
[out]:{'a': 1, 'c': (4, 5), 'b': 0} #d2本身的值不发生变化
* 若需要改变dict本身的值,即若key不在dict中时,将默认值default作为key对应的值插入dict中,即插入dict[key]=default,以上诉求可通过dict.setdefault(key,default=None)
[in]:d2={'a': 1, 'c': (4, 5), 'b': 0}
d2.setdefault('a',0) # a在d2中,即返回d2['a']=1
[out]:1
[in]:d2.setdefault('d',0) # d不在d2中,即返回设置的默认值0
[out]:0
[in]:d2
[out]:{'a': 1, 'c': (4, 5), 'b': 0, 'd': 0} # 将'd': 0插入d2中
* 当默认值default需要指定为数据类型时,可使用defaultdict。具体可参见[How does collections.defaultdict work](https://stackoverflow.com/questions/5900578/how-does-collections-defaultdict-work),具体用法如下:
>> from collections import defaultdict
>> defaultdict(list) # 默认值将生成为list(),即[]
>> defaultdict(set) # 默认值将生成为set(),即()
>> defaultdict(str) #默认值将生成str
>> defaultdict(int) # 默认值将生成int
* 应用:将字词按照首字母分类
应用setdefault:
>> words=['apple','bat','bar','atom','book']
>> by_letter={}
>> for word in words:
>> by_letter.setdefault(word[0],[]).append(word)
>> by_letter
[out]: {'a': ['apple', 'atom'], 'b': ['bat', 'bar', 'book']}
应用defaultdict:
>> from collections import defaultdict
>> by_letter1=defaultdict(list)
>> for word in words:
>> by_letter1[word[0]].append(word)
>> by_letter1
[out]:defaultdict(list, {'a': ['apple', 'atom'], 'b': ['bat', 'bar', 'book']})
四、集合(Set)
4.1 集合创建
集合是一种无序但元素唯一的容器,可以看成是一种没有键值的字典。
(1)通过{}创建
>> set1={1,2,3,2}
>> set1
[out]:{1, 2, 3}
(2)通过set()创建
>> set2=set([2,4,5,6])
>> set2
[out]:{2, 4, 5, 6}
4.2 集合修改
4.2.1 增加元素
集合用内置的add方法增加元素。
>> set1.add(6)
>> set1
[out]:{1, 2, 3, 6}
4.2.2 删除元素
同list一样,集合set通过pop和remove删除元素。
>> set1.pop()
[out]:1 # list.pop是删除指定位置的元素,因集合set本身是无序的,所以set.pop是删除任意元素。
>> set1
[out]:{2, 3, 6}
>> set2.remove(5) # 与list.remove相同,set.remove也是删除指定元素值
>> set2
[out]:{2, 4, 6}
4.2.3 判断元素是否在集合中
与其它数据类型一样,通过in/not in 进行判断。
4.3 集合运算
运算类型 | 函数 | 说明 |
并集 | a.union(b) | 求a和b的并集,并赋值给新的集合 |
a.update(b) | 求a和b的并集,并赋值给a | |
交集 | a.intersection(b) | 求a和b的交集,并赋值给新的集合 |
a.intersection_update(b) | 求a和b的交集,并赋值给a | |
差集 | a.difference(b) | 求a和b的差集,并赋值给新的集合 |
a.difference_update(b) | 求a和b的差集,并赋值给a | |
补集 | a.symmetric_difference(b) | 求a和b的补集,并赋值给新的集合 |
a.symmetric_difference_update(b) | 求a和b的补集,并赋值给a | |
包含 | a.issubset(b) | 如果a包含于b,则返回True |
五、 列表、集合和字典的推导式
5.1 列表推导式
一般来说,需要使用for-if循环的语言,可简化使用列表推导式实现。格式为:[expression(value) for value in collection if condition(value)],意思是:对于集合类collection的值value,如符合某种条件,则按照expression(value)进行计算,并按照list形式输出。其等同于以下for-if循环语句:
>> result=[]
>> for value in collection:
>> if condition(value):
>> result.append(expression(value))
举例如下:将字母大于2个的单词大写
>> strings=['a','as','bat','car','done']
>> [string.upper() for string in strings if len(string)>2]
[out]:['BAT', 'CAR', 'DONE']
5.2 嵌套列表推导式
如果是多层for循环,则按照for循环的顺序编写列表推导式。如下将列表组成的元组,构成简单列表的例子,如下:
>> some_tuples = [(1, 2, 3), (4, 5, 6), (7, 8, 9)]
>> [x for tuple in some_tuples for x in tuple]
[out]: [1, 2, 3, 4, 5, 6, 7, 8, 9]