Python 的一些tricks

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進行索引/切片操作。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章