切片操作专题之numpy、pandas

切片操作专题

  • 1.for循环也能实现数组赋值,为什么还要切片?
    • 1.1 中小型数组的赋值
    • 1.2 大型数组的赋值
    • 1.3 为什么会这样?
  • 2.numpy之切片
  • 3.pandas之切片
    • 3.1 采用关键字
    • 3.2 转成numpy之后,采用第2节方法

1.for循环也能实现数组赋值,为什么还要切片?

numpy为例,切片除了使代码更简洁,还能带来其他好处吗?

for循环作为最直接的赋值手段,难道不能cover所有的问题?

带着疑问,用事实说话:

1.1 中小型数组的赋值

如下,原始数组为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数组切片的执行时间。

可见对于中小型数组,执行时间差别不大。

但是如果对于特别大的数组呢?

1.2 大型数组的赋值

原始数组现在变为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

这个时间就有相当大的差别了。

如果需要读取大量文件,再从文件中抽取部分数据,数据读取、提取这个时间会占到程序运行的相当一部分。

这时,使用切片的效益就非常可观了。

1.3 为什么会这样?

Book《Python数据科学手册》给出如下解释

numpy:关于数组切片有一点很重要也非常有用,那就是数组切片返回的是数组数据的视图,而不是数值数据的副本。

这一点也是 NumPy 数组切片和 Python 列表切片的不同之处:在 Python 列表中,切片是值的副本。

这种默认的处理方式实际上非常有用:它意味着在处理非常大的数据集时,可以获取或处理这些数据集的片段,而不用复制底层的数据缓存。

所以,我们就愉快地切片吧~

2.numpy之切片

上面例子中已有涉及,这里再赘述一点。
随机产生一个10*10numpy数组:

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这样的可迭代单元。

3.pandas之切片

首先创建一个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列,有两种切片方法:

3.1 采用关键字

col=["num","upper"]
df[col].values
#out:
array([[1, 'A'],
       [2, 'B'],
       [3, 'C']], dtype=object)

3.2 转成numpy之后,采用第2节方法

df.values[:,[0,2]]
#out:
array([[1, 'A'],
       [2, 'B'],
       [3, 'C']], dtype=object)

你可能感兴趣的:(python,numpy,pandas,切片)