推薦閱讀:清晰易懂的Numpy入門教程
Numpy是數據分析和科學計算的核心包,上文詳細介紹了Numpy的入門教程,本文將詳細介紹Numpy的高級特性,這些特性對於數據分析和處理非常重要。
來源:Machine Learning Plus翻譯:石頭
目錄
1. 如何獲取滿足條設定件的索引
2. 如何將數據導入和導出csv文件
3. 如何保存和加載numpy對象
4. 如何按列或行拼接numpy數組
5. 如何按列對numpy數組進行排序
6. 如何用numpy處理日期
7.高階numpy函數介紹
8. 小結
1. 如何獲取滿足條設定件的索引
上一文介紹根據數組是否滿足條件,輸出為True或False.
# 定義數組importnumpyasnparr_rand=np.array([8,8,3,7,7,0,4,2,5,2])#根據數組是否大於4,滿足為True,不滿足為Falseb=arr_rand>4b#> array([ True, True, False, True, True, False, False, False, True,False])若我們想得到滿足條件的索引,用np.where函數實現.
# 定位數組大於5的索引index_gt5=np.where(arr_rand>5)print("Positions where value > 5: ",index_gt5)#> Positions where value > 5: (array([0, 1, 3, 4]),) # 索引由索引得到滿足條件的值.
# 根據索引得到滿足條件的數組值arr_rand.take(index_gt5)#> array([[8, 8, 7, 7]])np.where也可以接受另兩個可選擇的參數x和y。當條件滿足時,輸出x,反之輸出y.
# 如果值大於5,輸出字符串'gt5',反之輸出'le5'np.where(arr_rand>5,'gt5','le5')#> array(['gt5', 'gt5', 'le5', 'gt5', 'gt5', 'le5', 'le5', 'le5', 'le5', 'le5'],dtype='<U3')np.argmax和np.argmin分別獲取數組最大值和最小值的索引.
# 最大值索引print('Position of max value: ',np.argmax(arr_rand))# 最小值索引print('Position of min value: ',np.argmin(arr_rand))#> Position of max value: 0#> Position of min value: 5np.max和np.min分別獲取數組的最大值和最小值.
# 最大值print('max value: ',np.max(arr_rand))# 最小值print('min value: ',np.min(arr_rand))#> max value: 8#> min value: 0
2. 如何將數據導入和導出csv文件
導入數據的標準方法是使用np.genfromtxt函數,它可以從web URLs導入數據,處理缺失值,多種分隔符,處理不規則的列數等功能。一個不太通用的版本是用np.loadtxt函數導入數據,它假設數據集無缺失值.
作為示例,我們嘗試從下面的URL讀取.csv文件,由於numpy數組的所有元素都應該是同一種類型,因此文本的最後一列默認為'nan'。通過設置參數'filling_values',你可以用其他值代替缺失值.
# 關閉數字的科學表示方法np.set_printoptions(suppress=True)# 從url的csv文件導入數據path='https://raw.githubusercontent.com/selva86/datasets/master/Auto.csv'# delimiter:分隔符,skip_header:從多少行開始讀數據,以0開始,filling_values:缺失值表示,dtype:數據類型data=np.genfromtxt(path,delimiter=',',skip_header=1,filling_values=-999,dtype='float')data[:3]# 顯示前3行數據#> array([[ 18. , 8. , 307. , 130. , 3504. , 12. , 70. ,#> 1. , -999. ],#> [ 15. , 8. , 350. , 165. , 3693. , 11.5, 70. ,#> 1. , -999. ],#> [ 18. , 8. , 318. , 150. , 3436. , 11. , 70. ,#> 1. , -999. ]])若設置參數dtype為'object'或'None',np.genfromtxt在未設置佔位符的前提下能同時處理具有數字和文本列的數據集.
# data2 = np.genfromtxt(path, delimiter=',', skip_header=1, dtype='object')data2=np.genfromtxt(path,delimiter=',',skip_header=1,dtype=None)data2[:3]# 顯示前三行#> array([( 18., 8, 307., 130, 3504, 12. , 70, 1, b'"chevrolet chevelle malibu"'),#> ( 15., 8, 350., 165, 3693, 11.5, 70, 1, b'"buick skylark 320"'),#> ( 18., 8, 318., 150, 3436, 11. , 70, 1, b'"plymouth satellite"')],#> dtype=[('f0', '<f8'), ('f1', '<i8'), ('f2', '<f8'), ('f3', '<i8'), ('f4', '<i8'), ('f5', '<f8'), ('f6', '<i8'), ('f7', '<i8'), ('f8', 'S38')])最後,'np.savetxt'將數據保存為csv文件.
# 保存數據為csv文件np.savetxt("out.csv",data,delimiter=",")
3. 如何保存和加載numpy數據
Numpy提供了.npy和.npz文件類型來實現。如果保存一個ndarray數據,使用np.save保存為.npy文件;若保存多個ndarray數據,使用np.savez保存為.npz文件。加載numpy數據,則統一用np.load函數.
# 保存單一的numpy數據,使用.npy文件np.save('myarray.npy',arr2d)# 保存多個numpy數據,使用.npz文件np.savez('array.npz',arr2d_f,arr2d_b)# 加載.npy文件a=np.load('myarray.npy')print(a)#> [[0 1 2]#> [3 4 5]#> [6 7 8]]加載.npz文件,獲取特定的數組值.
# 加載.npz文件b=np.load('array.npz')print(b.files)b['arr_0']#> ['arr_0', 'arr_1']#> array([[ 0., 1., 2.],#> [ 3., 4., 5.],#> [ 6., 7., 8.]])雖然通過'arr_0'和'arr_1'獲取了數組值,但是我們對這兩個索引比較陌生,下面介紹手動設置索引保存和加載數組.
# 增加索引保存數據b=np.savez('array.npz',arr2d_f=arr2d_f,arr2d_b=arr2d_b)c=np.load('array.npz')print(c.files)c['arr2d_f']#> ['arr2d_f', 'arr2d_b']#> array([[1., 2., 3., 4.],[3.,4.,5.,6.],[5.,6.,7.,8.]])
4. 如何按列或行拼接numpy數組
本節介紹三種拼接numpy數組的方法:
方法1:設置np.concatenate參數axis的值為1或0,實現數組的列拼接或行拼接。方法2:np.vstack和np.hstack方法3:np.r_和np.c_
需要注意的是,np.r_和np.c_使用方括號來拼接數組,其他兩種方法使用括號。
首先,定義兩個需要拼接的數組.
# 定義兩個拼接的數組a=np.zeros([4,4])b=np.ones([4,4])print(a)print(b)#> [[ 0. 0. 0. 0.]#> [ 0. 0. 0. 0.]#> [ 0. 0. 0. 0.]#> [ 0. 0. 0. 0.]]#> [[ 1. 1. 1. 1.]#> [ 1. 1. 1. 1.]#> [ 1. 1. 1. 1.]#> [ 1. 1. 1. 1.]]行拼接數組
# 行拼接數組np.concatenate([a,b],axis=0)np.vstack([a,b])np.r_[a,b]#> array([[ 0., 0., 0., 0.],#> [ 0., 0., 0., 0.],#> [ 0., 0., 0., 0.],#> [ 0., 0., 0., 0.],#> [ 1., 1., 1., 1.],#> [ 1., 1., 1., 1.],#> [ 1., 1., 1., 1.],#> [ 1., 1., 1., 1.]])列拼接數組
# 列拼接np.concatenate([a,b],axis=1)np.hstack([a,b])np.c_[a,b]#> array([[ 0., 0., 0., 0., 1., 1., 1., 1.],#> [ 0., 0., 0., 0., 1., 1., 1., 1.],#> [ 0., 0., 0., 0., 1., 1., 1., 1.],#> [ 0., 0., 0., 0., 1., 1., 1., 1.]])
5. 如何按列對數據進行排序
本節介紹三種按列排序方法:np.sort,np.argsort和np.lexsort。在介紹三種排序方法前,先定義一個2維數組.
arr=np.random.randint(1,6,size=[8,4])arr#> array([[3, 3, 2, 1],#> [1, 5, 4, 5],#> [3, 1, 4, 2],#> [3, 4, 5, 5],#> [2, 4, 5, 5],#> [4, 4, 4, 2],#> [2, 4, 1, 3],#> [2, 2, 4, 3]])np.sort基於列對arr數組進行排序.
# axis=0表示列排序,1表示行排序np.sort(arr,axis=0)#> array([[1, 1, 1, 1],#> [2, 2, 2, 2],#> [2, 3, 4, 2],#> [2, 4, 4, 3],#> [3, 4, 4, 3],#> [3, 4, 4, 5],#> [3, 4, 5, 5],#> [4, 5, 5, 5]])由上面結果分析,np.sort排序函數認為所有列是相互獨立的,對所有列進行排序,破壞了每行的結構,
使用np.argsort函數可以保留行的完整性 .
# 對arr的第一列進行排序,返回索引sorted_index_1stcol=arr[:,0].argsort()# 根據第一列的索引對數組排序,保留了行的完整性arr[sorted_index_1stcol]#> array([[1, 5, 4, 5],#> [2, 4, 5, 5],#> [2, 4, 1, 3],#> [2, 2, 4, 3],#> [3, 3, 2, 1],#> [3, 1, 4, 2],#> [3, 4, 5, 5],#> [4, 4, 4, 2]])倒轉argsort索引實現遞減排序
# 遞減排序arr[sorted_index_1stcol[::-1]]#> array([[4, 4, 4, 2],#> [3, 4, 5, 5],#> [3, 1, 4, 2],#> [3, 3, 2, 1],#> [2, 2, 4, 3],#> [2, 4, 1, 3],#> [2, 4, 5, 5],#> [1, 5, 4, 5]])若要基於多個列對數組進行排序,使用np.lexsort函數,它的參數是元組類型,元組的每個元素表示數組的某一列,排序規則是:越靠近右邊的列,優先級越高.
# 先比較第一列,第一列相同的情況下再比較第二列lexsorted_index=np.lexsort((arr[:,1],arr[:,0]))arr[lexsorted_index]#> array([[1, 5, 4, 5],#> [2, 2, 4, 3],#> [2, 4, 5, 5],#> [2, 4, 1, 3],#> [3, 1, 4, 2],#> [3, 3, 2, 1],#> [3, 4, 5, 5],#> [4, 4, 4, 2]])
6. 如何用Numpy處理日期
np.datatime64創建日期對象,精確度達到納秒,你可以使用標準的YYYY-MM-DD格格式的字符串作為參數創建日期.
# 創建datetime64對象date64=np.datetime64('2018-02-04 23:10:10')date64#> numpy.datetime64('2018-02-04T23:10:10')從datatime64對象分離時間
# 從datatime64對象分離時間dt64=np.datetime64(date64,'D')dt64#> numpy.datetime64('2018-02-04')如果你想增加天數或其他任何時間單元,比如月份,小時,秒等,使用np.timedelta函數非常方便.
# np.delta建立多個時間單元tenminutes=np.timedelta64(10,'m')# 10 分鐘tenseconds=np.timedelta64(10,'s')# 10 秒鐘tennanoseconds=np.timedelta64(10,'ns')# 10 納秒print('Add 10 days: ',dt64+10)# 增加10天print('Add 10 minutes: ',dt64+tenminutes)# 增加10分鐘print('Add 10 seconds: ',dt64+tenseconds)# 增加10秒print('Add 10 nanoseconds: ',dt64+tennanoseconds)# 增加10納秒#> Add 10 days: 2018-02-14#> Add 10 minutes: 2018-02-04T00:10#> Add 10 seconds: 2018-02-04T00:00:10#> Add 10 nanoseconds: 2018-02-04T00:00:00.000000010dt64對象轉化為字符串
# dt64轉化為字符串np.datetime_as_string(dt64)#> '2018-02-04'np.is_busday函數判斷日期是否為工作日,工作日默認為周一至周五.
print('Date: ',dt64)print("Is it a business day?: ",np.is_busday(dt64))#> Date: 2018-02-04#> Is it a business day?: False # False表示不是手動設置工作日的時間,如設置工作日為周六周日,其他時間為休息日.
date64=np.datetime64('2019-04-14')# 設置周六周日為工作日np.is_busday(date64,weekmask='Sat Sun')#> Truenp.busday_offset查看後幾個工作日的日期.
# 周四date64=np.datetime64('2019-04-11')# 查看兩個工作日後的日期t=np.busday_offset(date64,2)t#> numpy.datetime64('2019-04-15')若當前工作日為非工作日,則默認是報錯的.
# 周六date64=np.datetime64('2019-04-13')# 查看兩個工作日後的日期t=np.busday_offset(date64,2)t#> ValueError: Non-business day date in busday_offset # 非工作日不能作為busday_offset的參數可以增加參數forward或backward來報錯,forward的含義是若當前日期非工作日,那麼往前尋找最接近當前日期的工作日,backward的含義則是往後尋找最接近當前日期的工作日.
#當前時間為周六(2019-04-13),往前最接近當前時間的工作日是2019-04-15,兩個工作日偏移後的日期是2019-04-17print("Add 2 business days, rolling forward to nearest biz day: ",np.busday_offset(date64,2,roll='forward'))#當前時間為周六(2019-04-13),往後最接近當前時間的工作日是2019-04-12,兩個工作日偏移後的日期是2019-04-16print("Add 2 business days, rolling backward to nearest biz day: ",np.busday_offset(date64,2,roll='backward'))#> Add 2 business days, rolling forward to nearest biz day: 2019-04-17#> Add 2 business days, rolling backward to nearest biz day: 2019-04-166.1 如何創建日期序列
np.arange可簡單創建日期序列
# 建立日期序列dates=np.arange(np.datetime64('2018-02-01'),np.datetime64('2018-02-10'))print(dates)# 檢查是否為工作日np.is_busday(dates)#> ['2018-02-01' '2018-02-02' '2018-02-03' '2018-02-04' '2018-02-05'#> '2018-02-06' '2018-02-07' '2018-02-08' '2018-02-09']array([True,True,False,False,True,True,True,True,True],dtype=bool)6.2 如何把numpy.data64對象轉化為datatime.datatime對象
# np.datetime64類型轉化為datetime.datetime類型importdatetimedt=dt64.tolist()dt#> datetime.date(2018, 2, 4)獲取datatime對象的年月日非常簡便
print('Year: ',dt.year)print('Day of month: ',dt.day)print('Month of year: ',dt.month)print('Day of Week: ',dt.weekday())# 周五#> Year: 2018#> Day of month: 4#> Month of year: 2#> Day of Week: 6
7. 高階numpy函數介紹
7.1 標量函數的向量化
標量函數只能處理標量,不能處理數組
# 定義標量函數deffoo(x):ifx%2==1:returnx**2else:returnx/2# On a scalarprint('x = 10 returns ',foo(10))print('x = 11 returns ',foo(11))#> x = 10 returns 5.0#> x = 11 returns 121# 函數不能處理數組# print('x = [10, 11, 12] returns ', foo([10, 11, 12])) # 錯誤np.vectorize使標量函數也能處理數組,可選參數otypes為輸出的類型.
# 函數向量化,向量化的輸出類型是floatfoo_v=np.vectorize(foo,otypes=[float])print('x = [10, 11, 12] returns ',foo_v([10,11,12]))print('x = [[10, 11, 12], [1, 2, 3]] returns ',foo_v([[10,11,12],[1,2,3]]))#> x = [10, 11, 12] returns [ 5. 121. 6.]#> x = [[10, 11, 12], [1, 2, 3]] returns [[ 5. 121. 6.]#> [ 1. 1. 9.]]7.2 apply_along_axis函數
首先定義一個二維數組
# 定義一個4x10的隨機二維數組np.random.seed(100)arr_x=np.random.randint(1,10,size=[4,10])arr_x#> array([[9, 9, 4, 8, 8, 1, 5, 3, 6, 3],#> [3, 3, 2, 1, 9, 5, 1, 7, 3, 5],#> [2, 6, 4, 5, 5, 4, 8, 2, 2, 8],#> [8, 1, 3, 4, 3, 6, 9, 2, 1, 8]])如果我們要找數組每行或每列的最大值,numpy的一個最大特點是基於向量化操作的,因此我們使用np.apply_along_axis函數找每行或每列的最大值.
# 基於列操作,找每列的最大值print('max of per column: ',np.apply_along_axis(np.max,0,arr=arr_x))# 基於行操作,找每行的最大值print('max of per row: ',np.apply_along_axis(np.max,1,arr=arr_x))#> max of per column: [9 9 4 8 9 6 9 7 6 8]#> max of per row: [9 9 8 9]7.3 searchsorted函數
np.searchsorted函數返回某一變量在有序數組的位置,在該位置插入變量後數組仍然是有序的.
# 生成有序數組x=np.arange(10)print('Where should 5 be inserted?: ',np.searchsorted(x,5))# 若遇到相同大小的數值,輸入變量放在右邊位置print('Where should 5 be inserted (right)?: ',np.searchsorted(x,5,side='right'))#> Where should 5 be inserted?: 5#> Where should 5 be inserted (right)?: 67.4 如何增加數組維度
在不增加任何額外數據的前提下,np.newaxis函數可以增加數組的維數,newaxis在的位置就是要增加的維度.
# 定義一維數組x=np.arange(5)print('Original array: ',x)# 數組維度為2print('ndims of x:',x.ndim)# 列維度增加x_col=x[:,np.newaxis]print(x_col)# 數組維度為2print('ndims of x_col: ',x_col.ndim)print('x_col shape: ',x_col.shape)# 行維度增加x_row=x[np.newaxis,:]print(x_row)print('x_row shape: ',x_row.shape)# 數組維度為2print('ndims of x_row: ',x_row.ndim)#> Original array: [0 1 2 3 4]#> ndims of x: 1#> [[0][1][2][3][4]]#> ndims of x_col: 2#> x_col shape: (5, 1)#> [[0 1 2 3 4]]#> x_row shape: (1, 5)#> ndims of x_row: 27.5 Digitize函數
np.digitize函數返回數組每個元素屬於bin的索引位置.
# 構建數組和binx=np.arange(10)bins=np.array([0,3,6,9])# 返回bin索引位置np.digitize(x,bins)#> array([1, 1, 1, 2, 2, 2, 3, 3, 3, 4])可視化分析digitize算法原理:
如上圖,根據變量落在bin的區間範圍,返回對應的索引.
7.7 Clip函數
np.clip函數將數字限制在給定截止範圍內,所有小於範圍下限的數被當成下限值,大於範圍上限的數被當成上限值.
# 限制x的所有元素位於3和8之間np.clip(x,3,8)#> array([3, 3, 3, 3, 4, 5, 6, 7, 8, 8])7.8 Histogram函數和Bincount函數
np.bincount函數統計最小值到最大值的個數,最小值為0.
# Bincount例子x=np.array([1,1,2,3,2,4,4,5,6,6,6])np.bincount(x)# 0出現0次, 1出現2次, 2出現2次, 3出現1次,4出現2次,5出現1次,6出現3次#> array([0, 2, 3, 0, 2, 1, 3], dtype=int64)np.histogram函數統計數據落入bins的區間,不考慮bins兩側的區間(如下圖所示).