1. numpy 拼接
有的時候需要動態numpy的一些array拼接在一起,例如:
從本地磁盤讀入txt或者npy文件,解析出array,然後把所有本地txt中的array拼接成一個大的numpy格式的array。
這個時候有2種思路:
(1)先把每一個array都讀入,然後一起拼接
(2)一邊讀入一邊拼接
1.1
先把每一個array都讀入,然後一起拼接
這裏用到2個工具:
- 列表表達式
- np.concatenate
列表表達式代替for循環,可以加快讀取的速度,並且把讀入的所有array組成一個list;
np.concatenate把list合併成一個大的array。
如下示例中的:
features = np.concatenate([np.load(f) for f in files], axis=0)
其中np.load(f)是把本地的npy文件讀入到內存,axis=0表示拼接行,列不變。
完整示例:
def get_features(path):
features = []
files = sh.find(path, '-type', 'f', '-name', '*.npy')
files = [f.strip() for f in files]
features = np.concatenate([np.load(f) for f in files], axis=0)
return features
1.2
一邊讀入一邊拼接
這種方法的本質是進行多次2個array的拼接。一般可以使用np.append。
由於不能一次拼接多個,所以不可以使用列表表達式,需要通過for循環實現。
這個方法的難點在第一次循環時,只有一個array無法append。所以解決辦法有2個(雖然都不優雅):
(1)先讀入一個array,然後循環從下一個開始
(2)在循環之前先造一個空的array
1.2.1
方法(1):
def get_features(path):
features = []
files = sh.find(path, '-type', 'f', '-name', '*.npy')
files = [f.strip() for f in files]
features = np.load(files[0])
for i in range(1, len(files )):
features = np.append(features, np.load(files[i]), axis=0)
return features
1.2.2
方法(2):
def get_features(path):
features = []
files = sh.find(path, '-type', 'f', '-name', '*.npy')
files = [f.strip() for f in files]
features = np.array([])
for f in files:
arr = np.load(f)
features = np.append(features.reshape(-1, arr.shape[1]), array), axis=0)
return features
不論從優雅度、效率還是代碼行數,1.1方法都比1.2方法好。所以推薦使用1.1方法。
2. 切片操作
這裏分爲兩個,python的切片和numpy的切片。
操作符: [start:end:step]
有點類似於c++ 裏面的三目運算符。
其中start,end,step以及第二個冒號:都可以省略。
2.1 python和numpy都有的切片操作
a = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
# 前6個
>>> a[:6]
[0,1,2,3,4,5]
# 後3個
>>> a[-3:]
[7,8,9]
# 取偶數
>>> a[::2]
[0,2,4,6,8]
# 取奇數
>>> a[1::2]
[1,3,5,7,9]
# 逆序
>>>a[::-1]
[9,8,7,6,5,4,3,2,1,0]
2.2 python獨有的切片操作
# 插入操作
>>> a[:0] = ['a', 'b'] # 開始前插入
['a','b',0,1,2,3,4,5,6,7,8,9]
>>> a[len(a):] = ['c', 'd'] # 最後插入
[0,1,2,3,4,5,6,7,8,9,'c', 'd']
>>> a[3:3] = ['m','n'] #中間某個位置插入
[0,1,2,'m','n',3,4,5,6,7,8,9]
# 替換
>>> a[:3] = ['p','q']
['p','q',3,4,5,6,7,8,9]
# 刪除
>>> del a[2:5]
[0,1,5,6,7,8,9]
2.3 numpy 獨有的切片操作
2.3.1 numpy中的索引
numpy中的索引有兩種,(1)索引數組 (2)布爾數組
索引數組:
# 一維數組索引
>>> a = np.array([0,1,2,3,4,5,6,7,8,9])
[0 1 2 3 4 5 6 7 8 9]
>>> i = np.array([1,3,5,4,2])
>>> a[i]
array([1, 3, 5, 4, 2])
>>> i2 = np.array([[1,3,5],[2,4,6]])
>>> a[i2]
array([[1, 3, 5],
[2, 4, 6]])
# 二維數組索引
按第一個維度索引
>>> a = np.array([[1,2,3],[4,5,6]])
[[1 2 3]
[4 5 6]]
>>> a[[0,0,1]]
array([[1, 2, 3],
[1, 2, 3],
[4, 5, 6]])
>>> i = np.array([1,0,1])
>>> a[i]
array([[4, 5, 6],
[1, 2, 3],
[4, 5, 6]])
# 用True False list代替切片表達式
>>> arr1 = np.arange(10)
[0 1 2 3 4 5 6 7 8 9]
>>> arr1[[True, False, True, False, True, False, True, False, True, False]]
[0,2,4,6,8]
#
>>> arr2 = np.array([[1,2,3,4,5,6,7,8],[2,3,4,5,6,7,8,9], [3,4,5,6,7,8,9,0]])
[[1 2 3 4 5 6 7 8]
[2 3 4 5 6 7 8 9]
[3 4 5 6 7 8 9 0]]
>>> arr2[[True, True, False], ::-2]
[[8 6 4 2]
[9 7 5 3]]
布爾數組:
>>> a = np.arange(12).reshape(3,4)
[[ 0 1 2 3]
[ 4 5 6 7]
[ 8 9 10 11]]
>>> b = a>4
>>> print(b)
[[False False False False]
[False True True True]
[ True True True True]]
>>> a[b]
array([ 5, 6, 7, 8, 9, 10, 11])
>>> a[[True, True, False], :]
array([[0, 1, 2, 3],
[4, 5, 6, 7]])
>>> a[:, [True, False, True, False]]
array([[ 0, 2],
[ 4, 6],
[ 8, 10]])
2.3.2 索引和切片相結合
主要在多維切片的時候比較好用,不容易混淆。
比方說我有一個3行4列的數組,需要其中的1 2行和1 3列組成一個新的數組
>>> a = a = np.arange(12).reshape(3,4)
[[ 0 1 2 3]
[ 4 5 6 7]
[ 8 9 10 11]]
>>> a[:2][:, [True, False, True, False]]
array([[0, 2],
[4, 6]])
其中a[:2] 先得到數組array([[0, 1, 2, 3],[4, 5, 6, 7]]), 然後後面的[:, [True, False, True, False]]把1 3列提取出來了。
其中布爾數組還可以和np.where結合
>>> a = np.arange(12)
>>> print(a)
[ 0 1 2 3 4 5 6 7 8 9 10 11]
>>> b = np.where((a>3)&(a<9))
>>> print(b)
(array([4, 5, 6, 7, 8]),)
>>> a[b]
array([4, 5, 6, 7, 8])
>>> c = (a>3)&(a<9)
>>> print(c)
[False False False False True True True True True False False False]
>>> a[c]
array([4, 5, 6, 7, 8])
注意 (a>3) & (a<9) 中的兩個括號不能省略。
另外, (a>3) & (a<9)得到的是一個布爾數據,np.where((a>3)&(a<9))得到的是索引數組。這兩種方式都可以對a進行索引/切片操作。