python数据分分析
数据处理的步骤
目的:如何用python操作数据
对象:需要的是结构化的数据
工具:用到的库
库名 | 用途 |
---|---|
Numpy | |
Pandas | |
matplotlib | |
JupyterNotebook | |
Scipy | |
Scikit-learn | |
Statsmodels |
python的内建数据结构;元组、列表、字典
元组
>tuple = (4,5,6)
元组的拆包特性:
>tuple = (4,5,6)
>a,b,c = tup
>b
5
嵌套元组的拆包特性
>tuple = 4,5,(6,7)
>a,b,(c,d) = tuple
>d
7
利用元组的拆包特性,实现交换
>a,b =1,2
>b,a = a,b
>a
2
>b
1
python自带的更高级的拆包特性:*rest(余下的部分),帮助你从某个起始部分采集数据
>values = 1,2,3,4,5,6
>a,b,*rest = values
>rest
[4,5,6]
一般为了方便,开发者会用 *_
代替*rest
来表示非采集部分的变量
元组的统计计数:count,统计某个元素出现的次数
>a = (1,2,2,2,3,4,4,2)
>a.count(2)
4
元组和列表的区别:可变与不可变。
列表
增加与移除元素的方法
- 增加到尾巴:append
- 插入到任意位置:insert
- 移除元素:pop、
- 移除第一个符合的元素:remove
不考虑性能,可以使用append和remove,将python列表作为一个完全合适的数据结构
查找元素
- 查找元素是否在列表中:in
- 查找元素是否不在列别中: not in
列表的查找性能很差
列表与“字典和集合”相比,检查列表中是否有一个值,是非常缓慢的,这是因为python在列表中是线性逐个扫描的机制,而在集合和字典中是全局同时。
python数据结构 | 检查方式 |
---|---|
列表 | 逐个扫描 |
字典、集合 | 全局扫描 |
性能更好的添加列表的方式
用“+”号可以添加列表内容,但因为这样链接过程创建了新的列表,是一种相对高代价的操作(内存占用),所以使用
extend
将元素加到已存在的列表是更好的方式。
排序:sort
- 正常引用sort用大小排序
- 给排序附加条件:(key=)
b.sort(ley = len) #按字符长度排序
使用二分搜索并将值插到合适的位置
bisect.bisect:找到元素应被插入的位置,保持排序
bisect.insort:将元素插入到对应位置
import bisect
> c = [1,2,2,2,3,4,7]
> bisect.bisect(c,2) # 排序2,显示应该排队位置在4。位置从0开始,此时并未插入元素
> 4
> bisect.bisect(c,5) # 5对应排序,显示应该排队位置在6,位置从0开始,此时并未插入元素
> 6
> bisect.insort(c,6) # 插入6,此时插入元素
> c
> [1,2,2,2,3,4,6,7]
需要注意:
bisect并不会检测列表是否自己排序,如果对未排序的列表使用bisect,他能用但结果不一定正确。
切片
切片基本上使用[start:stop]
这种形式.。
负索引可以反着搜索。
步进值:[::2]
如果需要对元组或者列表进行翻转,可以将步进值传入-1:
[::-1]
构建索引:enumerate(翻译成中文:列举、枚举)
for i,v in enumerate(list): # i是索引,v是值
比如我们要构建索引:
> some_list = ["foo","bar","baz"]
> mapping = {}
> for i,v in enumerate(some_list):
> mapping[v] = i
> mapping
{"foo":1,"bar:2","baz":3}
按照顺序排列,然后出一个新序列:sorted
> sorted([7,1,2,2,6,0,3,2])
[0, 1, 2, 2, 3, 6, 7]
> sorted("horse race")
[' ', 'a', 'c', 'e', 'e', 'h', 'o', 'r', 'r', 's']
配对zip
> seq1 = ["foo","bar","baz"]
> seq2 = ["one","two","three"]
> zipped = (seq1,seq2)
> list(zipped)
[['foo', 'bar', 'baz'], ['one', 'two', 'three']]
zip处理的长度由最短的序列决定
> seq3 =[False,True]
> list(zip(seq1,seq2,seq3))
[('foo', 'one', False), ('bar', 'two', True)]
zip的使用场景:同时遍历多个序列
> 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的使用场景:行列置换
> people = [("ZQ","She"),("Kate","Liu"),("Sopu","Wu")]
> first_names,last_names = zip(*people)
> first_names
('ZQ', 'Kate', 'Sopu')
> last_names
('She', 'Liu', 'Wu')
倒序排序:reversed
reversed是一个生成器(生成器:没有实例的时候,是不会产生一个倒序的列表)
> list(reversed(range(10)))
[9, 8, 7, 6, 5, 4, 3, 2, 1, 0]
字典dict
{key:value} 键值对,添加
empty_dict = {}
d1 = {"a":"some value","b":[1,2,3.4]}
print(d1)
d1[7] = "an integer" #添加键值对
print(d1)
> {'a': 'some value', 'b': [1, 2, 3.4]}
> {'a': 'some value', 'b': [1, 2, 3.4], 7: 'an integer'}
只能搜索键,不能搜索值:in
"b" in d1
> True
删除的两种方式:del,pop
d1[5] = "some value"
d1["dummy"]="another value"
print(d1)
> {'a': 'some value', 'b': [1, 2, 3.4], 7: 'an integer', 5: 'some value', 'dummy': 'another value'}
del d1[5] # 直接删除模式
d1
> {'a': 'some value','b': [1, 2, 3.4],7: 'an integer','dummy': 'another value'}
remo = d1.pop("dummy") #先存储返回值
d1 #然后才能删除
> {'a': 'some value', 'b': [1, 2, 3.4], 7: 'an integer'}
迭代器:返回的keys值,values值
list(d1.keys())
> ['a', 'b', 7]
list(d1.values())
> ['some value', [1, 2, 3.4], 'an integer']
d1.update({"b":"foo","c":12}) # update可以用来合并两个字典
d1
> {'a': 'some value', 'b': 'foo', 7: 'an integer', 'c': 12}
- 排序会乱:update方法改变了字典中元素位置,
- 会覆盖相同的:因此对于任何原字典中已经存在的键,如果传给update方法的数据也含有相同的键,则它的值将会被覆盖。
两个序列按元素配对
mapping ={}
for key,value in zip(key_list,value_list):
mapping[key]=value #构建字典
字典的本质是:含有两个元素的元组,基于这个原理,我们可以用“元组”的数据结构来构建“字典”
mapping={}
dict(zip(range(5),reversed(5))) #用两个元组构建字典
mapping
> {0:4,1:3,2:2,3:1,4:0} # 构建字典成功
还有一种字典推导式
设置默认值
第一种解题方法:通常情况下的代码逻辑:
if key in some_dict:
value = some_dict[key]
else:
value = default_value
第二种解题方法:get方法 和 pop方法
value = some_dict.get(key,default_value)
会在不是字典的时候发生的情况:
- get方法,返回none
- pop方法,抛出异常
你能想象一个场景,用一些字词组组成数据结构“列表”
words = ["apple","bat","bar","atom","book"]
接下来实现一个要求:1.分类
by_letter = {}
for word in words:
letter = word[0]
if letter not in by_letter:
by_letter[letter] = [word] # 以首字母形成字典
else:
by_letter[letter].append(word) # 在字典内部添加
by_letter
> {"a":["apple","atom"],"b":["bat","bar","book"]}
实现分类更简单的方法
字典的setdefault方法,实现分类
for word in words:
letter = word[0]
by_letter.setdefault(letter,[]).append(word)
内建得集合模块类:defaultdict,实现分类功能
from collections import defaultdict
by_letter = defaultdict(list) # 传入类型
for word in words:
by_letter[word[0]].append(word)
字典中得“键"是不可变得对象:所以我引用了哈希值得概念,我们可以使用哈希函数让值变得唯一。
hash('string') # 字符串是唯一得
>
hash((1,2,(2,3))) # 元组是唯一得
>
hash((1,2,[2,3])) # 列表是可变得,所以会哈希失败
>
为了将列表作为键、一种方式就是将其转换成元组。元组内部可以哈希化,它就可以哈希化。
集合:set
集合得特性:无序、唯一、支持数学意义上得集合操作(交集、差集、并集、对成差集等)
创建方式:set函数、或者大括号{}。
set([2,2,2,1,3,3])
> {1,2,3}
{2,2,2,1,3,3}
> {1,2,3}
并集(集合得合并) :union 和符号 "|"
a = set([1,2,3,4,5])
b = set([3,4,5,6,7,8])
a.union(b)
> {1,2,3,4,5,6,7,8}
a | b
> {1,2,3,4,5,6,7,8}
交集:intersection 和符号"&"
a.intersection(b)
> {3,4,5}
a & b
> {a & b}
python集合得操作
函数 | 等效 | 作用 |
---|---|---|
a.add(x) | N/A | 将元素x加入集合a |
a.clear | N/A | 重置集合为空,清空所有元素 |
a.remove(x) | N/A | 从集合a中移除x元素 |
a.pop() | N/A | 移除任意元素,如果为空,则抛出keyError |
a.union(b) | a | b | 并集 |
a.upadate(b) | a | =b | 将a所有得元素设置成b得并集 |
a.intersection(b) | a & b | 交集 |
a.inersection_update(b) | a & =b | 将a设置成b得交集 |
a.difference(b) | a-b | 在a不在b得元素 |
a.symmetric_difference(b) | a ^ b | 所有在a或b中,但不是同时在a、b中元素 |
a.symmetric_difference_update(b) | a ^ =b | 将a的内容设为所有在a或b中,但不是同时在a、b中的元素 |
a.issubset | N/A | 如果a包含于b返回True |
代码效率的问题:效率更高的代码形式
c =a.copy()
c |=b
c
> {1,2,3,4,5,6,7,8}
d = a.copy()
d &= b
d
{3,4,5}
如何想包含列表型元素,必须转换成元组。
my_data= [1,2,3,4]
my_set = {tuple(my_data)}
my_set
> {(1,2,3,4)}
你可以检查一个集合是否是另一个集合的子集or超集
a_set = [1,2,3,4]
{1,2,3}.issubset(a_set)
> True
a_set.issuperset({1,2,3})
> True
当且仅当两个集合的内容一摸一样时,两个集合才相等
{1,2,3} == {3,2,1}
> True
python的语言特性,推导式:列表、集合、字典的推导式
- 允许你过滤一个容器的元素
- 用一种简明的表达式转换传递给过滤器的元素
- 从而生成一个新的列表
[expr for var in collection if conditon]
等价于
result = []
for var in collection:
if condition:
result.append(expr)
列表的推导式操作:[在这括号里面敲代码]
strings = ["a","as","bat","car","dove","python"]
[x.upper() for x in strings if len(x)>2]
> ["BAT","CAR","DOVE","PYTHON"]
集合与字典的推导式:是列表推导式的自然扩展
字典的推导式:{key:value的代码}
dict_dump = {key-expr : value-expr for value in collection if condition}
集合的推导式:{集合用大括号}
set_comp = {expr for value in collection if condition}
使用map函数获得类似的表达:
set(map(len,strings)) # 创建一个由strings变量的长度组成的集合
> {1,2,3,4,6}
map函数的作用:为指定序列做映射。
创建一个字符串与其位置相匹配的字典:
loc_mapping = {val:index for index,val in enumerate(strings)}
loc_mapping
> {"a":0,"as":1,"bat":2,"car":3,"dove":4,"python":5}
多层嵌套推导式
some_tuples = [(1,2,3),(4,5,6),(7,8,9)]
flattened = [x for tup in some_tuples for x in tup]
函数def
def my_function(x,y,z=1.5)
return
- 特性:
如果没有return,则自动返回None
x和y是位置函数,z是关键字函数
函数的主要限制是关键词参数,必须在位置参数后。
全局变量 global,通常全局变量用来存储系统中的某些状态,如果你发现你大量使用了全局变量,可能你需要面向对象编程(使用类)
返回多个值:数据分析中经常需要返回多个值,用来干啥不知道
函数是对象:用来去除空格、移除标点符号、调整大小写等
利用正则表达式,这章节有个非常华丽的操作:
我们正常使用使用正则表达式来去除空格、移除标点符号、调整大小写的操作步骤
- 去除空格: strip()
- 移除标点符号:re.sub("[! #? ]","",value)
- 调整大小写:title()
import re
def clean_strings(strings):
result=[]
for value in strings:
value = value.strip() # 1
value = re.sub("[! #? ]","",value) # 2
value = value.title() # 3
result.append(value)
return result
一个非常华丽的操作:用一个列表来代替上面的1,2,3步骤
def remove_punctuation(value):
return re.sub("[! #? ]","",value) # 设置一个去除标点的函数,方便下文引用
clean_ops = [str.strip,remove_punctuation,str.title] # 列表代替操作。
def clean_strings(strings,ops):
result = []
for value in strings:
for function in ops:
value = function(value)
result.append(value)
return result
以上模式我们撑之为 函数化,在更高层次上,使clean_strings函数更具有 复用性、通用性,接下来我们可以更进阶一点的。
for x in map (remove_punctuation,states):
print(x)
将函数传给map函数作为参数
for x in map(remove_punctuation,states):
print(x)
匿名函数lamda
匿名函数:
- 一种通过单个语句生成函数的方式,其结果是返回值。
- 使用lamda关键字定义
- 仅拜倒“我们声明一个匿名函数”的意思
def short_function(x):
return x*2
equiv_anon = lamda x: x*2
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)
# 也能写成这样的
[X*2 for x in inits]
根据字串中不同字母的数量对一个字符串集合进行排序
strings = ["foo","card","bar","aaaa","abab"]
strings.sort(key = lambda x:len(set(list(x)))) #将一个匿名函数传给列表的sort方法
strings
> ["aaaa","foo","abab","bar","card"]
和def关键字声明的函数不同,匿名函数对象自身并没有一个显示_name_属性,这是lambda函数被称为匿名函数的一个原因
柯里化:部分参数应用
以数学家(Haskell Curry)命名,通过部分参数应用的方式从已有的函数中衍生出新的函数。
def add_number(x,y):
return x+y
使用上述函数,我们可以衍生出一个只有一个变量的新函数add_five
add_five = lambda y : add_numbers(5,y)
第二个参数对于函数add_numbers就是柯里化了,这里什么神奇的地方,只是定义了一个新函数,而且这个新函数调用了已经存在的函数。
from functools import partial
add_five = partial (add_numbers,5)
生成器
在认识生成器之前,我们需要了解迭代器
迭代器的作用:
- 用于在上下文中,向python解释器生成对象的对象。
- 在python语言中,一切都是对象,迭代器本身也是对象
一个 for循环的逻辑,迭代器、生成器相继出场。
生成器是啥?
生成器:是构造新的可遍历对象的一种非常简洁的方式。
普通函数 | 生成器 |
---|---|
执行并一次返回单个结果 | 返回一个多结果的序列 |
生成器函数的特点:
1.暂停:在每一个元素产生之后暂停
2.下一个请求:暂停直到下一个请求
3. yield:如需创建一个生成器,只需要将函数中的return 替换成 yield
def squares(n=10):
print("Generating squares from 1 to {0}".format(n**2))
for i in range(1,n+1):
yield i**2
当你实际调用生成器时,代码并不会立即执行
gen = squares()
gen
> 结果会报错 <generator object squares at 内存地址>
直到请求生成器中的元素,它才会执行它的代码。
for x in gen:
print(x,end=" ")
> Generating squares from 1 to 100 1 4 9 16 25 36 49 64 81 100
创建生成器表达式
生成器表达式,只需要将列表推导式的中括号"[]"替代为小括号"()"即可
gen = (x ** 2 for x in range(100))
gen
> <generator object <genexpr> at 内存地址>
等价:
def _make_gen():
for x in range(100):
yield x ** 2
gen = _make_gen()
很多情况下,生成器表达式可以用来替换列表推导式:
sum (X ***2 for x in range(100))
>
dict((i,i **2) for i in range(5))
>
标准库中的itertools模块
itertools模块适用于大多数数据算法的生成器集合。
groupby可以根据任意的序列和一个函数,通过函数的返回值对序列中连续的元素进行分组。
import itertools
first_letter = lambda x:x[0]
names = {"Alan","Adam","Wes","Will","Albert","Steven"}
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"]
函数 | 描述 |
---|---|
combinations(iterable,k) | 根据iterable参数中的所有元素,生成一个可能的序列,忽略顺序 |
permutations(iterable,k) | 根据iterable参数中所有元素按顺序生成包含所有可能K元组的序列 |
groupby(iterable[,keyfunc]) | 根据每一个独一的key生成(key,subiterator)元组 |
product(*iterable,repeat=1) | 以元组的形式,根据输入的可遍历对象胜场笛卡尔积、与嵌套的for循环类似 |
错误处理和异常处理
def attempt_float(x):
try:
return float(x)
except:
return x
比如我只想处理ValueError:
def attempt_float(x):
try:
return float(x)
except ValueError:
return x
比如我想处理多个错误
def attempt_float(x):
try:
return float(x)
except (TypeError,ValueError):
return x
比如我想让一部分代码无论try是否报错都要执行
f = open(path,"w")
try:
write_to_file(f)
finally:
f.close()
这样我们可以让程序结束后总是关闭
f = open(path,"w")
try:
write_to——file(f)
except:
print("Failed")
else:
print("successeded")
finally:
f.close()
Ipython中的异常
Ipython解释器 比 普通python解释器 高级的地方
- Ipython解释器提供更多的额外的上下文(报错信息),可用
%mode
命令来控制上下文数量呢! - 可以从plain(普通)模式切换到Verbose(复杂)模式
- 在错误发生后,进入异常堆栈(使用
debug
或者pdb
命令)进行交互式事后调试
python中处理数据文件,不用pandas的情况
打开文件进行读取、写入
python的文件模式 | 描述 |
---|---|
r | 只读模式 |
w | 只写模式,重名文件则被删除 |
x | 只写模式,存在重名则创建失败 |
a | 添加到已存在的文件,文件不存在就创建 |
r+ | 读写模式 |
b | 二进制文件模式,一般需要添加到别的模式中:“rb”,“wb” |
t | 文件文本模式,默认解码编码“Unicode”,可指定其他编码,可添加其他模式中:“rt”,“wt” |
对于可读文件,常用的方法:read、seek、tell
原理 | 概述 |
---|---|
read | 通过读取字节数来推进文件句柄的位置 |
tell | 给出句柄当前的位置 |
# 文件里面的内容是:01234567890
f = open(path)
f.read(10)
> "01234567890"
f2 = open(path,"rb") # binary mode
f2.read(10)
>
有时候会出现编码格式引起的变化,尽管读取了10个字符,但当前句柄位置为11。
f.tell()
>11
f2.tell()
>10
这是因为默认编码下需要那么多字节(11)对10个字母进行解码。可以用sys模块来检查文件的默认编码
# 检查默认编码
import sys
sys.getdefaultenoding()
>"utf-8"
seek可以将句柄位置改变到文件中特定的字节
f.seek(3)
> 2
f.read(1)
>
"2"
#最后去,请牢记,关闭文件
f.close()
f2.close()
Numpy
Numpy的效率比python块100倍,且占用内存更小
多维数组:Numpy ndarray
读作:n-darray
import numpy as np
# 生成随机数组
data = np.random.randn(2,3)
data
>
# 给data加上一个数学操作
data * 10
data + data
#方阵数学
一个ndarray是一个通用的多维同类数据容器,也就是说,它包含的每一个元素均为相同类型。每一个数组都有一个shape属性,用来表征数组每一维度的数量;每一个数组都有一个dtype属性,用来描述数组的数据类型。
属性 | 描述 |
---|---|
shape | 数组每一维度的数量(多少行,多少列) |
dtype | 描述数组的数据类型 |
生成ndarry
生成数组最简单的方式就是使用array函数
data1 = [6,7.5,8,0,1]
arr1 = np.array(data1)
arr1
> array([6.,7.5,8.,0.,1.])
同等长度的列表会自动转换多维数组
data2 = [[1,2,3,4],[5,6,7,8]]
arr2 = np.array(data2)
arr2
> array([[1,2,3,4],[5,6,7,8]])
# 利用ndim,shape来确认这一点特性。
arr2.ndim
> 2
arr2.shape
> (2,4)
除非显式指定,不然np.array会自动推断生成数组的数据类型。
arr1.dtype
> dtype("float64")
arr2.dtype
> dtype("int64")
给定长度和形状后,
- zeros可以一次性创造全0数组。
- ones可以一次性创造全1数组。
- empty则可以创建一个没有初始化数值的数组。
- 想要创建高维数组,则需要为shanpe传递一个元组。
np.zeros(10)
> array([0.,0.,0.,0.,0.,0.,0.,0.,0,.0])
np.zeros((3,6))
> ([0.,0.,0.,0.,0.,0.],[0.,0.,0.,0.,0.,0.],[0.,0.,0.,0.,0.,0.])
np.empty((2,3,2))
array([[0.,0.,0.],[0.,0.,0.],[0.,0.,0.]],[[0.,0.,0.],[0.,0.,0.],[0.,0.,0.]])
用empty来生成一个全0数组,并不安全,有些时候他可能会返回未初始化的垃圾数值。
arange是python内建函数range的数组版,是内建函数不是ndarry函数。
np.arange(15)
array([0,1,2,3,4,5,6,7,8,9,10,11,12,13,14])
不公平并不意味着你有绝对正确
函数名 | 描述 |
---|---|
array | |
asarray | 将输入转换成ndarry,如果已经是ndarry则不再复制 |
arange | python内建函数 |
ndarray的数据类型
- dtype:
- dtype是Numpy能够与其他系统数据灵活交互的原因。比如C和Fortran
- 当你需要在内存或者硬盘上做更深入的存取操作时,尤其是大数据集时,你才真正需要了解存储的数据类型
类型 | 类型代码 | 描述 |
---|---|---|
int8,uint8 | i1,u1 | 有符号和无符号的8位整数 |
int16,uint16 | i2,u2 | 有符号和无符号的16位整数 |
int32,uint32 | i4,u4 | 有符号和无符号的32位整数 |
int64,uint64 | i8,u8 | 有符号和无符号的64位整数 |
float16 | f2 | |
float32 | f4或f | 标准单精度浮点数,兼容C语言float |
float64 | f8或d | 保准双精度浮点数,兼容C语言double和python float |
float128 | f16或g | 拓展精度浮点数 |
complex64 | c8 | 基于32位浮点数的复数 |
complex128 | c16 | 基于64位浮点数的复数 |
complex256 | c32 | 基于128位浮点数的复数 |
bool | ? | 布尔值,存储True或False |
object | O | python object类型 |
string_ | S | 修正ASC Ⅱ字符串类型,例如:生成一个长度为10的字符串类型,使用“S10” |
unicode_ | U | 修正Unicode类型,例如:生成一个长度为10的Unicode类型,使用“U10” |
转换数据类型:astype
astype会生成一个新的数组。
arr = np.array([1,2,3,4,5])
arr.dtype
> dtype("int64") # 原本的数据类型是整数
float_arr = arr.astype(np.float64) # 将整数转换成浮点数
float_arr.dtype
> dtype("float64")
“常规” 转换成 ”数字“
numeric_strings = np.array(["1.25","-9.6","42"],dtype = np.string_)
numeric_strings.astype(float)
> array([ 1.25,-9.6,42. ])
某些原因会导致转换失败
比如:用python内建的float代替np.float64,因为字符串转换成float64位,将会抛出ValueError
格式刷:使用另一组数的dtype
int_array = np.arange(10)
calibers = np.array([.22,.270,.357,.380,.44,.50],dtype = np.float64)
int_array.astype(calibers.dtype)
> array([0.,1.,2.,3.,4.,5.,6.,7.,8.,9.])
向量化:Numpy允许批量操作,无需任何for循环。
- 标量计算得问题:
能不能对单独某个列或者行进行标量计算
-
标量布尔运算,例如大于小于等于,返回True or False。
-
广播特性:不同尺寸的数组间的操作需要用到广播特性。
Numpy基础索引和切片
数据来源 | 概念区别 |
---|---|
python内建列表 | 理论上它产生的切片是一个复制 |
Numpy数组索引 | 它产生的切片是一个视图,对视图的任何修改都会体现在原数组上 |
arr = np.arange(10)
arr[5:8] = 12
arr
> array([0,1,2,3,4,12,12,12,8,9])
arr_slice = arr[5:8]
arr_sliece
> array([12,12,12])
# 不写切片值得[:]将会引用数组得所有值。
arr[:] = 0
arr
> array([0,0,0,0,0,0,0,0,0,0])
在一个二维数组中,每一个索引值对应得元素不再是一个值,而是一个一维数组:
arr2d = np.array([1,2,3],[4,5,6],[7,8,9])
arr2d[2]
> array([7,8,9])
因此,单个元素可以通过递归得方式获得。
一维:只有一行
参数 | 数据1 | 数据2 | 数据3... |
---|---|---|---|
0 | 1 | 2 | 3 |
二维:
0 | 1 | 2 | 3 |
---|---|---|---|
0 | 0,1,2 | 2,0,3 | 4,5,7 |
1 | 1,0,2 | 3,5,7 | 7,7,7 |
2 | 9,7,6 | 5,5,4 | 3,0,0 |
三维:
arr3d = np.array([[1,2,3],[4,5,6]] , [[7,8,9],[10,11,12]])
arr3d[1,0] #对索引值的探索。
> array([7,8,9])
数组的切片索引
arr2d[:2] #数组沿着0轴进行切片,含义是选择arr2d的前两“行”
arr2d[1,:2] #选择第二行但是只选择前两列
arr2d[:2,2] #选择第三列,但是只选择前两行
索引切片:下索引-->上索引,少一个位置。
布尔索引
- 有一组人名,我们要选择所有叫做“Bob”的行。
- 首先生成一个含盖人名的数组names,然后生成随机数data
names = np.array(["Bob","Joe","Will","Bob","Will","Joe","Joe"])
data = np.random.randn(7,4) # randn生成随机正态分布数据,数据7行4列
- 假设data和names一一对应
- 选中所偶“Bob”的行,这个操作并没有关联data的数据,所以要看第6步
names = "Bob"
- 这个时候Numpy会产生一个新数组,这个数组就是布尔数组。
# 用于比较names数组和字符串“Bob”
array([True,False,False,True,False,False,False],dtype = bool)
- 然后往data数组中传入布尔值进行索引
data [names == "Bob"]
> array ([[xxx,xxx,xxx,xxx],[xxx,xxx,xxx,xxx]])
1. 布尔数组的长度必须和数组轴索引长度一致。虽然不一致并不会报错,但会出问题
2. 可以用切片或者整数值对布尔值进行混合和匹配
索引Bob行,并切片想要的列
data [names == "Bob",2:] #Bob行,从2号索引列后面所有的列
data [names == "Bob",3] #Bob行,筛选3号列
选择除Bob以外的其他数据
- 对条件取反
- "~"表示对通用条件取反
names != "Bob"
data = [~(names == "Bob")]
选择“多个”时,对多个布尔值进行联合,“& (and)”、“| (or)”
mask = (namse == "Bob") | (names == "Will")
mask
array([True,False,True,True.True,Fasle,False],dtype = bool)
data[mask]
1. 使用布尔值索引选择数据,总是生成数据的拷贝
2. Python的关键字and和or对布尔值数组并没有用,需要用“&”和“|”来替换
将data中所有的负值设置成“0”
data[data < 0 ] = 0
Numpy的专业术语:神奇的索引,利用数组对Numpy数组进行索引
- 用于描述使用整数数组进行数据索引
arr = np.empty([8,4]) - 符合特定顺序的子集
# 假设有一个8*4的数组
arr = np.empty((8,4))
for i in range(8):
arr[i] = i
# 这里面都是索引值
arr[[4,3,0,6]]
# 最后索引出数列
> array([[4,4,4,4],
[3,3,3,3],
[0,0,0,0],
[6,6,6,6]])
多个索引数组时的情况。
生成一个8*4的矩阵
arr = np.arange(32).reshape((8,4))
arr[[1,5,7,2],[0,3,1,2]] # 一维
arr[[1,5,7,2]] [:,[0,3,1,2]] # 二维
索引值 | 0 | 1 | 2 | 3 |
---|---|---|---|---|
0 | 0 | 1 | 2 | 3 |
1 | 4 | 5 | 6 | 7 |
2 | 8 | 9 | 10 | 11 |
3 | 12 | 13 | 14 | 15 |
4 | 16 | 17 | 18 | 19 |
5 | 20 | 21 | 22 | 23 |
6 | 24 | 25 | 26 | 27 |
7 | 28 | 29 | 30 | 31 |
对应举证切片的对应单元格,索引值,0开始。
行 | 列 | 代表值 |
---|---|---|
1 | 0 | 4 |
5 | 3 | |
7 | 1 | |
2 | 2 |
不考虑数组的维数(例子中是二维),神奇索引的结果总是一维的。在这样的背景下,我们要切出一个二维数组的操作。
首先arr[[1,5,7,2]]
索引了二维数组中的1752四行,而arr[:,[0,3,1,2]]
则表示,冒号“:”表示索引出全部行,而[0,3,1,2]
对应索引出来的列。
切片解释的插图
数组转置和换轴
- 转置是一种特殊的数据重组形式
通用函数:ufunc,在ndarray中进行逐元素操作的函数
使用数组表达式来实现多种数据操作任务,来代替显示循环的方法。
线性代数:方阵数学问题
伪随机数数生成
随机漫步,随机能否可控?
编制模块
``