以numpy
为例,切片除了使代码更简洁,还能带来其他好处吗?
for
循环作为最直接的赋值手段,难道不能cover所有的问题?
带着疑问,用事实说话:
如下,原始数组为20000*100
,将它其中的20列赋值给一个数组20000*20
。
通过for循环以及numpy数组切片的执行时间各位多少呢?
import time
import numpy as np
import random
size=20000
a=np.random.randint(0,100,(size,100),dtype=np.int8)
b=np.random.choice(range(100),20)
t0=time.time()
c1=np.zeros((size,len(b)))
for i in range(len(b)):
c1[:,i]=a[:,b[i]]
t1=time.time()
c2=a[:,b]
t2=time.time()
print(f"time cost1:{t1-t0}s")
print(f"time cost2:{t2-t1}s")
输出结果如下:
time cost1:0.0020225048065185547s
time cost2:0.000997304916381836s
cost1、cost2分别为for循环以及numpy数组切片的执行时间。
可见对于中小型数组,执行时间差别不大。
但是如果对于特别大的数组呢?
原始数组现在变为20000000*100
,同样将其20列赋值给另外一个数组。
import time
import numpy as np
import random
size=20000000
a=np.random.randint(0,100,(size,100),dtype=np.int8)
b=np.random.choice(range(100),20)
t0=time.time()
c1=np.zeros((size,len(b)))
for i in range(len(b)):
c1[:,i]=a[:,b[i]]
t1=time.time()
c2=a[:,b]
t2=time.time()
print(f"time cost1:{t1-t0}s")
print(f"time cost2:{t2-t1}s")
输出结果如下:
time cost1:7.487896680831909s
time cost2:2.3806240558624268s
这个时间就有相当大的差别了。
如果需要读取大量文件,再从文件中抽取部分数据,数据读取、提取这个时间会占到程序运行的相当一部分。
这时,使用切片的效益就非常可观了。
Book《Python数据科学手册》给出如下解释:
numpy:关于数组切片有一点很重要也非常有用,那就是数组切片返回的是数组数据的视图,而不是数值数据的副本。
这一点也是 NumPy 数组切片和 Python 列表切片的不同之处:在 Python 列表中,切片是值的副本。
这种默认的处理方式实际上非常有用:它意味着在处理非常大的数据集时,可以获取或处理这些数据集的片段,而不用复制底层的数据缓存。
所以,我们就愉快地切片吧~
上面例子中已有涉及,这里再赘述一点。
随机产生一个10*10
的numpy
数组:
import numpy as np
a=np.random.randint(0,10,(8,8))
#out:
array([[7, 4, 3, 6, 8, 6, 7, 3],
[7, 0, 5, 3, 1, 2, 9, 5],
[1, 7, 5, 4, 1, 9, 4, 4],
[4, 7, 3, 5, 6, 7, 5, 1],
[5, 1, 8, 7, 4, 7, 0, 8],
[4, 4, 7, 8, 2, 0, 3, 1],
[1, 3, 1, 4, 3, 9, 4, 5],
[1, 2, 6, 9, 7, 8, 8, 3]])
如果是针对连续单元切片,如截取2到4行:
a[2:5,:]
#out:
array([[1, 7, 5, 4, 1, 9, 4, 4],
[4, 7, 3, 5, 6, 7, 5, 1],
[5, 1, 8, 7, 4, 7, 0, 8]])
但是如果截取指定行或者指定列呢?如截取2,4,7行:
b=[2,4,7]
a[b,:]
#out:
array([[1, 7, 5, 4, 1, 9, 4, 4],
[5, 1, 8, 7, 4, 7, 0, 8],
[1, 2, 6, 9, 7, 8, 8, 3]])
这里b=[2,4,7]
,np.array([2,4,7])
,还是b=(2,4,7)
,对于切片操作来说,都是类似于:3
这样的可迭代单元。
首先创建一个pandas DataFrame对象。
import pandas as pd
a=pd.Series([1,2,3])
b=pd.Series(["a","b","c"])
c=pd.Series(["A","B","C"])
d=pd.Series(["#","¥","%"])
df=pd.DataFrame({
"num":a,"lower":b,"upper":c,"other":d})
#out:
num lower upper other
0 1 a A #
1 2 b B ¥
2 3 c C %
如果要读取其第0列和第2列,有两种切片方法:
col=["num","upper"]
df[col].values
#out:
array([[1, 'A'],
[2, 'B'],
[3, 'C']], dtype=object)
df.values[:,[0,2]]
#out:
array([[1, 'A'],
[2, 'B'],
[3, 'C']], dtype=object)