跳转至

8.12.数据处理

Windows 10
Python 3.7.3 @ MSC v.1915 64 bit (AMD64)
Latest build date 2020.04.12
numpy version:  1.18.1
ary = copy.deepcopy(np.arange(16).reshape(4,4))
ary
array([[ 0,  1,  2,  3],
       [ 4,  5,  6,  7],
       [ 8,  9, 10, 11],
       [12, 13, 14, 15]])

获取符合条件的元素的索引

最大元素的索引

print(np.argmax(ary))
print(np.argmax(ary, axis=1))
print(ary.argmax(axis=1))
15
[3 3 3 3]
[3 3 3 3]

如果只是想找出最大值:

print(np.amax(ary))
# np.max是np.amax的别名
print(np.max(ary, axis=0))
print(ary.max())
print(ary.max(axis=0))
15
[12 13 14 15]
15
[12 13 14 15]

最小元素的索引

np.argmin(ary)
0

如果只是想找出最小值:

np.amin(ary)
0

按大小排序的索引

np.argsort(a, axis=-1, kind=None, order=None)
  • kind'quicksort', 'mergesort', 'heapsort', 'stable'。指定排序算法。默认为 'quicksort'

  • order:如果是结构化数组,可以用order参数指定按照数组的字段顺序排序。

ary2 = np.array([1, 4, 3, 2, 0, 9, 8, 5, 7])
# 由小到大排序
ary2.argsort()
ary2[ary2.argsort()]
array([0, 1, 2, ..., 7, 8, 9])
np.argpartition(a, kth, axis=-1, kind='introselect', order=None)
  • kth:从小到大排序前kth个元素。因为是不完全排序,因此比argsort的效果更高。

  • kind'introselect'。指定排序算法。默认为 'introselect'

  • order:如果是结构化数组,可以用order参数指定按照数组的字段顺序排序。

ary2 = np.array([1, 4, 3, 2, 0, 9, 8, 5, 7])
# kth 为非负数: 从小到大排序
print(ary2.argpartition(2))
print(ary2[ary2.argpartition(2)])
# kth 为负数: 从大到小排序
print(ary2[ary2.argpartition(-2)])
[4 0 3 ... 6 7 8]
[0 1 2 ... 8 5 7]
[0 1 5 ... 7 8 9]

非零数的索引

np.nonzero会返回非零元素的索引(这意味着nan的索引也会被返回)。

print("符合条件的索引:")
pprint.pprint(np.nonzero(ary))
# ary.nonzero()
ary[np.nonzero(ary)]
符合条件的索引:
(array([0, 0, 0, ..., 3, 3, 3], dtype=int64),
 array([1, 2, 3, ..., 1, 2, 3], dtype=int64))
array([ 1,  2,  3, ..., 13, 14, 15])

指定条件

np.where(condition),当condition为真,则返回元素的索引:

print("符合条件的索引:")
pprint.pprint(np.where(ary>5))
ary[np.where(ary>5)]
符合条件的索引:
(array([1, 1, 2, ..., 3, 3, 3], dtype=int64),
 array([2, 3, 0, ..., 1, 2, 3], dtype=int64))
array([ 6,  7,  8, ..., 13, 14, 15])

np.where(condition)实际上是np.asarray(condition).nonzero()的快捷方式。

ary[np.asarray(ary>5).nonzero()]
array([ 6,  7,  8, ..., 13, 14, 15])

如果只是想得到符合条件的元素,不需要索引,使用mask数组是一个方便的方法:

pprint.pprint(ary>5)
ary[ary>5]

# np.nanargmax(ary)
array([[False, False, False, False],
       [False, False,  True,  True],
       [ True,  True,  True,  True],
       [ True,  True,  True,  True]])
array([ 6,  7,  8, ..., 13, 14, 15])

缺失值处理

nan_ary = np.arange(16, dtype=np.float32).reshape(4,4)
nan_ary[3,2] = np.NAN
nan_ary[1,1] = np.nan
nan_ary
array([[ 0.,  1.,  2.,  3.],
       [ 4., nan,  6.,  7.],
       [ 8.,  9., 10., 11.],
       [12., 13., nan, 15.]], dtype=float32)

使用np.isnan ufunc 函数得到mask数组:

np.isnan(nan_ary)
array([[False, False, False, False],
       [False,  True, False, False],
       [False, False, False, False],
       [False, False,  True, False]])

这样就可以轻松地将nan填充为常量:

nan_ary[np.isnan(nan_ary)]
# nan_ary[np.isnan(nan_ary)] = 2
array([nan, nan], dtype=float32)

如果想得到nan值的索引:

np.where(np.isnan(nan_ary))
(array([1, 3], dtype=int64), array([1, 2], dtype=int64))

如果想丢弃存在nan值的行:

np.delete(nan_ary, np.where(np.isnan(nan_ary))[0], axis=0)
array([[ 0.,  1.,  2.,  3.],
       [ 8.,  9., 10., 11.]], dtype=float32)

统计存在nan值的行(样本)所占的比列也很简单:

len(np.where(np.isnan(nan_ary))[0]) / nan_ary.shape[0]
0.5

如果想将nan值填充为非常量(比如平均值、中位数等),这就要先计算出平均值,再对nan数据逐个进行填充。

填充边缘

np.pad(nan_ary, pad_width=1, mode="mean")
array([[ nan,  6. ,  nan,  nan,  9. ,  nan],
       [ 1.5,  0. ,  1. ,  2. ,  3. ,  1.5],
       [ nan,  4. ,  nan,  6. ,  7. ,  nan],
       [ 9.5,  8. ,  9. , 10. , 11. ,  9.5],
       [ nan, 12. , 13. ,  nan, 15. ,  nan],
       [ nan,  6. ,  nan,  nan,  9. ,  nan]], dtype=float32)