日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > python >内容正文

python

利用python进行数据分析_从删库到跑路

發布時間:2024/3/7 python 29 豆豆
生活随笔 收集整理的這篇文章主要介紹了 利用python进行数据分析_从删库到跑路 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

目錄

前言

一 numpy模塊

1.numpy的數據結構:多維數組ndarray

數組轉置和軸對換

矩陣內積

通用函數

利用數組進行數據處理(矢量化)

將條件邏輯表述為數組運算

數組和統計法方法?

約簡

排序sort

唯一化和其他集合邏輯

數組中的集合運算

用于數組的文件輸入輸出

線性代數

隨機數生成

部分numpy.random函數

隨即漫步

數組重塑

扁平化或散開

C和Fortran順序

數組的合并與拆分

元素的重復操作:tile和repeat

花式索引的等價函數:take和put

廣播

三維數組的廣播

ufunc高級應用

自定義ufunc

結構化和記錄式數組

嵌套dtype和多維字段

排序

間接排序:argsort和lexsort

在有序數組中查找元素:searchsorted方法和digitize函數

numpy的matrix類

內存映像文件

性能建議

Cpython和numpy

二 pandas模塊

1.pandas的數據結構:Series和DataFrame

三 matplotlib模塊

四? ? scipy模塊


?

@python3.6.6;ubuntu18.04

前言

常用模塊為numpy、pandas、matplotlib、scipy

代碼編寫工具:jupyter

一 numpy模塊

1.numpy的數據結構:多維數組ndarray

Numpy最重要的一個特點就是其N維數組對象ndarray,ndarray是一個通用的同構數據多維容器,也就是說其中所有的元組必須是相同類型的,他接收一切序列類型的對象(包括其他數組)。Numpy的ndarray提供了一種將同質數據塊(可以是連續或非連續存儲的)解釋為多維數組對象的方式,數據類型dtype決定了數據的解釋方式,比如浮點數、整數、布爾值等

ndarray如此強大的原因部分是因為所有數組對象都是數據塊的一個跨度視圖(strided view),ndarray不只是一塊內存和一個dtype,它還有跨度信息,這使得數組能以各種步幅(step size)在內存中移動,更準確的說,ndarray由以下內容組成:

一個指向數組(一個系統內存塊)的指針

一個表示數組形狀(shape)的元組,如3*3的數組形狀元組為(3,3)

一個跨度元組(stride),其中整數指的是為了前進到當前緯度下一個元素需要跨過的字節數,如3*4*5的foalt64數組,其跨度為(160,40,8)

下圖簡單地說明了ndarray的內部結構

1.0 ndarray的數據類型(dtype)體系

你可能需要檢查數組中所包含的數據是否是整數、浮點數、字符串或python對象,因為浮點數的種類很多,判斷dtype是否屬于某個大類的工作非常繁瑣,但是,dtype都有一個超類(比如np.interger和np.floating),他們可以和np.issubdtype函數結合,調用dtype的mro方法即可查看dtype的所有父類(有些數據類型后面帶有下劃線,是為了和python的數據類型區別開來)

In [9]: ints=np.ones(10,dtype=np.uint16)In [10]: floats=np.ones(10,dtype=np.float32)In [11]: np.issubdtype(ints.dtype,np.integer)#判斷數據類型,同python的isinstance Out[11]: TrueIn [12]: np.issubdtype(floats.dtype,np.floating) Out[12]: True#調用dtype的mro方法即可查看其所有的父類In [13]: np.float64.mro() Out[13]: [numpy.float64,numpy.floating,numpy.inexact,numpy.number,numpy.generic,float,object]

下圖簡單說明了dtype體系以及父子類關系

1.1 創建數組

import numpy as np In [15]: np.array([1,2,3]) Out[15]: array([1, 2, 3])#傳入列表,產生一維數組In [16]: np.array([[1,2,3],[4,5,6]]) Out[16]: array([[1, 2, 3],[4, 5, 6]])#傳入嵌套列表,產生二維數組#傳入一個數組 In [22]: rnd=np.random.randn(12)In [23]: rnd_re=rnd.reshape(3,4)#reshape,重新構造數組結構In [24]: rnd Out[24]: array([ 0.65986137, 0.59780991, -0.29968381, -0.13900897, -0.91233434,-1.11650251, 0.10361076, -0.99113903, -0.18876077, -1.07867959,-1.35017413, -0.02826018])In [25]: rnd_re Out[25]: array([[ 0.65986137, 0.59780991, -0.29968381, -0.13900897],[-0.91233434, -1.11650251, 0.10361076, -0.99113903],[-0.18876077, -1.07867959, -1.35017413, -0.02826018]])In [26]: np.array(rnd_re) Out[26]: array([[ 0.65986137, 0.59780991, -0.29968381, -0.13900897],[-0.91233434, -1.11650251, 0.10361076, -0.99113903],[-0.18876077, -1.07867959, -1.35017413, -0.02826018]])

1.2 shape和dtype

shape表示各維度大小的元組,tdype用于說明數組數據類型的對象

In [1]: import numpy as npIn [2]: data=np.array([1,2,3])In [3]: data.shape Out[3]: (3,)In [4]: data=np.array([[1,2,3],[4,5,6]])In [5]: data.shape Out[5]: (2, 3)In [6]: data.dtype Out[6]: dtype('int64')

1.3 empty、zeros、ones

empty創建一個沒有任何具體值的數組(應該是無意義的虛數)

zeros創建一個全是0的數組

ones創建一個全是1的數組

In [30]: np.empty((3,3)) Out[30]: array([[1.96923895e-316, 2.04482388e-316, 3.92581470e+170],[2.33607195e-301, 5.94613337e-302, 2.29457644e+156],[3.66137200e-244, 4.10074486e-322, 3.95252517e-322]])In [32]: np.zeros((3,3)) Out[32]: array([[0., 0., 0.],[0., 0., 0.],[0., 0., 0.]])In [33]: np.ones((3,3)) Out[33]: array([[1., 1., 1.],[1., 1., 1.],[1., 1., 1.]])

1.4 arange

arange是python內置函數range的數組版

In [34]: np.arange(10) Out[34]: array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])

1.5 ndarray的數據類型

dtype(數據類型)是一個特殊對象,它含有ndarray將一塊內存解釋為特定數據類型所需的信息

主要有int64,int32,float64,float32等(不涉及底層工作,很少涉及,不用記)

#數值型dtype的命名方式相同:一個類型名(如int,float),后面跟一個表示各元素位長的數字,如float64 In [36]: np.array([1,2,3]).dtype Out[36]: dtype('int64')In [37]: data=np.array([1,2,3],dtype=np.float64)In [38]: data.dtype Out[38]: dtype('float64')

1.6 astype

通過astype可以顯式的轉換數組的數據類型

In [41]: data=np.array(['1','2','3'])In [42]: data.dtype Out[42]: dtype('<U1')In [43]: data.astype(np.float64)#注意:使用astype會創建出一個新的數組(即不改變原始數據) Out[43]: array([1., 2., 3.])#astype也可用作調用其他數組的數據類型 In [44]: data1=np.array([1,2,3])In [45]: data2=np.array(['1','2','3'])In [46]: data2.astype(data1.dtype) Out[46]: array([1, 2, 3])

1.7 數組和標量的運算

矢量化(vectorization),數組可以讓你不是用循環即可對數據執行批量運算,這通常叫做矢量化

數組和標量之間的運算,會將運算應用到元素級,同樣的,大小相等的數組之間的任何運算都會應用到元素級

廣播:不同大小數組之間的運算叫做廣播

In [47]: data=np.array([[1,2,3],[4,5,6]])In [49]: data*data Out[49]: array([[ 1, 4, 9],[16, 25, 36]])In [52]: data*3 Out[52]: array([[ 3, 6, 9],[12, 15, 18]])

1.8索引和切片

一維數組很簡單,類似python數據類型

In [53]: data=np.array([1,2,3])In [54]: data[1] Out[54]: 2

當你將一個標量值賦值給一個切片時,該值會自動傳播到整個選區,跟列表最重要的區別在于,數組切片是原始數據的視圖,即和數據不會被復制,視圖上的任何修改都會直接反映到源數據,若需要得到數組的副本,需要使用data.copy()顯式的復制

In [59]: data_arr=np.array([x for x in range(10)])In [61]: arr_slice=data_arr[5:8]In [62]: data_arr Out[62]: array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])In [64]: arr_slice Out[64]: array([5, 6, 7])In [65]: arr_slice[1]=12345In [66]: arr_slice Out[66]: array([ 5, 12345, 7])In [67]: data_arr Out[67]: array([ 0, 1, 2, 3, 4, 5, 12345, 7, 8,9]) #給數組arr_slice賦值,會改變其源數據data_arr,而列表則不會 In [68]: data_list=[x for x in range(10)]In [69]: list_slice=data_list[5:8]In [70]: data_list Out[70]: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]In [71]: list_slice Out[71]: [5, 6, 7]In [72]: list_slice[1]=12345In [73]: list_slice Out[73]: [5, 12345, 7]In [74]: data_list Out[74]: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] #使用copy()方法顯式的復制源數據,則不會修改源數據 In [75]: data_arr=np.array([x for x in range(10)])In [76]: data_arr Out[76]: array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])In [77]: arr_slice=data_arr[5:8].copy()In [78]: arr_slice Out[78]: array([5, 6, 7])In [79]: arr_slice=12345In [80]: arr_slice Out[80]: 12345In [81]: data_arr Out[81]: array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])

二維數組中,索引位置上的元素不再是標量,而是一維數組,因此對各個元素進行遞歸訪問需要的方法不同,其切片有兩種方法實現,其中第一種類似嵌套列表的切片

In [84]: data_arr=np.array([[x for x in range(10)],[x for x in range(10,20)]])In [85]: data_arr Out[85]: array([[ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9],[10, 11, 12, 13, 14, 15, 16, 17, 18, 19]])In [86]: data_arr[1][1] Out[86]: 11In [87]: data_arr[1,1] Out[87]: 11

三維數組,切片取值可以理解為三層嵌套列表,同樣可以使用兩種方法表達

In [90]: data_arr=np.array([[[x for x in range(10)],[x for x in range(10,20)]],[...: [x for x in range(20,30)],[x for x in range(40,50)]]])In [91]: data_arr Out[91]: array([[[ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9],[10, 11, 12, 13, 14, 15, 16, 17, 18, 19]],[[20, 21, 22, 23, 24, 25, 26, 27, 28, 29],[40, 41, 42, 43, 44, 45, 46, 47, 48, 49]]])In [95]: data_arr[1,1,1] Out[95]: 41In [92]: data_arr[1] Out[92]: array([[20, 21, 22, 23, 24, 25, 26, 27, 28, 29],[40, 41, 42, 43, 44, 45, 46, 47, 48, 49]])In [93]: data_arr[1][1] Out[93]: array([40, 41, 42, 43, 44, 45, 46, 47, 48, 49])In [94]: data_arr[1][1][1] Out[94]: 41

布爾型索引

跟算術運算一樣,數組的比較運算(如==)也是矢量花的,因此,對數據和字符串的比較運算將會產生一個布爾型數組,布爾型數組的軸長度跟被索引的數組的軸長度一致

In [105]: data=np.array(['a','b','c'])In [106]: data=='d' Out[106]: array([False, False, False])In [107]: data!='d' Out[107]: array([ True, True, True])

布爾型數組和整數數組混合使用

In [108]: data1=np.array(['a','b','c'])In [109]: data2=np.array([1,2,3])In [110]: data_boolean=data1=='a'In [111]: data_boolean Out[111]: array([ True, False, False])In [112]: data2[data_boolean] Out[112]: array([1])

布爾算術運算符:& |

python中的and和or在numpy中無效

In [108]: data1=np.array(['a','b','c']) In [109]: data2=np.array([1,2,3])In [121]: data_boolean=(data1=='a')&(data1=='b')In [122]: data_boolean Out[122]: array([False, False, False])In [123]: data_boolean=(data1=='a')|(data1=='b')In [124]: data_boolean Out[124]: array([ True, True, False])In [125]: data2[data_boolean] Out[125]: array([1, 2])

花式索引

花式索引(Fancy indexing)是一個Numpy術語,它指利用整數數組進行索引

#子集賦值 In [126]: arr=np.empty((8,4))In [127]: arr Out[127]: array([[1.78873028e-316, 6.92799192e-310, 6.92799191e-310,6.92799192e-310],[6.92799191e-310, 6.92799191e-310, 6.92799191e-310,6.92799191e-310],[6.92799191e-310, 6.92799191e-310, 6.92799192e-310,6.92799191e-310],[6.92799192e-310, 6.92799191e-310, 6.92799191e-310,6.92799192e-310],[6.92799191e-310, 6.92799191e-310, 6.92799192e-310,6.92799192e-310],[6.92799191e-310, 6.92799191e-310, 5.41734680e-317,6.92799191e-310],[6.92799191e-310, 6.92799191e-310, 6.92799191e-310,6.92799191e-310],[6.92799192e-310, 6.92799192e-310, 6.92799192e-310,6.92799191e-310]])In [128]: for i in range(8):...: arr[i]=i...: In [129]: arr Out[129]: array([[0., 0., 0., 0.],[1., 1., 1., 1.],[2., 2., 2., 2.],[3., 3., 3., 3.],[4., 4., 4., 4.],[5., 5., 5., 5.],[6., 6., 6., 6.],[7., 7., 7., 7.]])#為了以特定的順序選取子集,只需要傳入一個用于指定順序的整數列表或ndarray即可 In [130]: arr[[4,3,0,6]] Out[130]: array([[4., 4., 4., 4.],[3., 3., 3., 3.],[0., 0., 0., 0.],[6., 6., 6., 6.]]) #一次傳入多個索引數組會有一點特別,他返回一個一維數組,其中的元素對應各個索引元組In [133]: arr[[1,2,3,4],[5,6,7,0]]#第二個列表表示列的排序,不能超過3 --------------------------------------------------------------------------- IndexError Traceback (most recent call last) <ipython-input-133-b97868d57f0c> in <module>() ----> 1 arr[[1,2,3,4],[5,6,7,0]]IndexError: index 5 is out of bounds for axis 1 with size 4In [134]: arr[[1,4,5,7],[0,3,1,2]]#返回的是數組的第一列數據,即默認的索引 Out[134]: array([1., 4., 5., 7.])In [143]: arr[[1,4,5,7]][:,[0,3,1,2]]#前面的列表表示子集,后面列表表示選取的子集的數據排列 Out[143]: array([[ 4, 7, 5, 6],[16, 19, 17, 18],[20, 23, 21, 22],[28, 31, 29, 30]])#也可以使用np.ix_函數,它可以將兩個一維整數數組轉換為一個用于選取方形區域的索引 In [144]: arr[np.ix_([1,4,5,7],[0,3,1,2])] Out[144]: array([[ 4, 7, 5, 6],[16, 19, 17, 18],[20, 23, 21, 22],[28, 31, 29, 30]])

數組轉置和軸對換

transpose和T

簡單轉置用T,復雜用transpose

數組轉置是重塑的一種特殊形式,它返回的是源數據的視圖(不會進行任何復制),數組不僅有transpose方法,還有一個T屬性

In [5]: data=np.arange(12).reshape((3,4))In [6]: data Out[6]: array([[ 0, 1, 2, 3],[ 4, 5, 6, 7],[ 8, 9, 10, 11]])In [7]: data.T Out[7]: array([[ 0, 4, 8],[ 1, 5, 9],[ 2, 6, 10],[ 3, 7, 11]])

對于高維數組,transpose需要得到一個由軸編號組成的元組,才能對數組進行轉置

array([[[ 0, 1, 2, 3],[ 4, 5, 6, 7]],[[ 8, 9, 10, 11],[12, 13, 14, 15]]])In [12]: arr.transpose((1,0,2))#軸1和軸0互換,軸2不變,原本的順序是(0,1,2),分別表示總共有三個軸 Out[12]: array([[[ 0, 1, 2, 3],[ 8, 9, 10, 11]],[[ 4, 5, 6, 7],[12, 13, 14, 15]]])

矩陣內積

np.dot

In [9]: np.dot(data,data.T) Out[9]: array([[ 14, 38, 62],[ 38, 126, 214],[ 62, 214, 366]])

通用函數

即(ufunc)既是一種ndarray中的數據執行元素級運算的函數,你可以將其看作簡單函數的矢量花包裝器

簡單函數是指:接受一個或多個標量值,產生一個或多個標量值

sqrt和exp

接收一個變量的ufunc稱為一元ufunc,其他如add和maximum稱為二元ufunc

In [19]: arr=np.arange(10)In [20]: np.sqrt(arr)#平方根 Out[20]: array([0. , 1. , 1.41421356, 1.73205081, 2. ,2.23606798, 2.44948974, 2.64575131, 2.82842712, 3. ])In [21]: np.exp(arr)#以自然常數e為底數的指數函數,e是一個2.71828....的常數 Out[21]: array([1.00000000e+00, 2.71828183e+00, 7.38905610e+00, 2.00855369e+01,5.45981500e+01, 1.48413159e+02, 4.03428793e+02, 1.09663316e+03,2.98095799e+03, 8.10308393e+03])

add和maximum

In [22]: arr1=np.array([1,2,3])In [23]: arr2=np.array([4,5,6])In [24]: np.add(arr1,arr2)#數組1和數組2相加 Out[24]: array([5, 7, 9])In [29]: arr1=np.array([1,3,5])In [30]: arr2=np.array([1,2,6])In [31]: np.maximum(arr1,arr2)#取數組1和數組2對應元素的最大值,組成新數組 Out[31]: array([1, 3, 6])

以下表格是一些常見的通用函數

一元ufunc?
abs、fabs計算整數、浮點數和復數的絕對值,非復數,使用fabs更快
sqrt計算各元素的平方根,相當于arr**0.5
square計算各元素的平方,相當于arr**2
exp計算各元素指數e
log,log10,log2,log1p分別為自然對數(底數為e),底數為10的對數,底數為2的對數,log(1+x)
sign計算各元素的正負號,正為1,0為零,負為-1
ceil計算各元素的ceiling值,即大于等于該值的最小整數
floor計算各元素的floor值,即小于等于該值的最小整數
rint將各元素四舍五入到最接近的整數
modf將數組的元素的整數和小數部分以兩個獨立的數組返回
isnan返回一個哪些值是控制NaN的布爾型數組
isfinite,isinf是否是有窮(finite),是否是無窮的(isinf),返回一個布爾型數組
cos,cosh,sin,sinh,tan,tanh普通型和雙曲型三角函數
arccos,arccosh,arcsin,arcsinh,arctan,arctanh反三角函數
logical_not計算各元素not x的真值,相當于-arr
二元ufunc?
add將數組中對應元素相加
subtract將數組中對應元素相減
multiply數組元素相乘
divide,floor_divide除法,向下整除(去掉余數)
power對第一個數組中的元素A,根據第二個數組中的元素B,計算A的B次方
maximum,fmax元素級的最大值計算,fmax忽略NaN值
minimum,fimin元素級的最小值計算,fmin忽略NaN值
mod元素級的求模運算(除法的余數)
copysign將第二個數組的值的符號復制給第一個數組中的值
greater,greater_equal,less,less_equal,equal,not_equal元素級比較運算,最終產生布爾型數組
logical_and,logical_or,logical_xor

元素級邏輯運算,與或非,相當于&、|、^

??
??
??

利用數組進行數據處理(矢量化)

Numpy數組使多種數據處理任務可以簡單表述為數組表達式(否則需要寫循環)

用數組表達式替代循環的做法,通常稱作矢量化。

一般來說數組化運算要比純python的等價運算要快上一兩各數量級,尤其是各種數值運算

作為簡單的例子,假設我們想要在一組值(網格型)上計算函數sqrt(x^2+y^2)。np.meshgrid函數接受兩個一維數組,并產生兩個二維矩陣(對應于兩個數組中所有的(x,y)對):

In [48]: points=np.arange(-5,5,0.01)In [49]: x,y=np.meshgrid(points,points)In [50]: x Out[50]: array([[-5. , -4.99, -4.98, ..., 4.97, 4.98, 4.99],[-5. , -4.99, -4.98, ..., 4.97, 4.98, 4.99],[-5. , -4.99, -4.98, ..., 4.97, 4.98, 4.99],...,[-5. , -4.99, -4.98, ..., 4.97, 4.98, 4.99],[-5. , -4.99, -4.98, ..., 4.97, 4.98, 4.99],[-5. , -4.99, -4.98, ..., 4.97, 4.98, 4.99]])In [51]: y Out[51]: array([[-5. , -5. , -5. , ..., -5. , -5. , -5. ],[-4.99, -4.99, -4.99, ..., -4.99, -4.99, -4.99],[-4.98, -4.98, -4.98, ..., -4.98, -4.98, -4.98],...,[ 4.97, 4.97, 4.97, ..., 4.97, 4.97, 4.97],[ 4.98, 4.98, 4.98, ..., 4.98, 4.98, 4.98],[ 4.99, 4.99, 4.99, ..., 4.99, 4.99, 4.99]])In [53]: z=np.sqrt(x**2+y**2)In [54]: z Out[54]: array([[7.07106781, 7.06400028, 7.05693985, ..., 7.04988652, 7.05693985,7.06400028],[7.06400028, 7.05692568, 7.04985815, ..., 7.04279774, 7.04985815,7.05692568],[7.05693985, 7.04985815, 7.04278354, ..., 7.03571603, 7.04278354,7.04985815],...,[7.04988652, 7.04279774, 7.03571603, ..., 7.0286414 , 7.03571603,7.04279774],[7.05693985, 7.04985815, 7.04278354, ..., 7.03571603, 7.04278354,7.04985815],[7.06400028, 7.05692568, 7.04985815, ..., 7.04279774, 7.04985815,7.05692568]])

將條件邏輯表述為數組運算

np.where

np.where函數是三元表達式x if condition else y的矢量化版本。假設我們有一個布爾數組和兩個值數組

np.where的第二個和第三個參數不必是數組,它們都可以是標量值。在數據分析工作中,where通常用于根據另一個數組而產生一個新的數組。

In [56]: arr1=np.array([1,2,3,4,5])In [57]: arr2=np.array([-1,-2,-3,-4,-5])In [58]: arr3=np.array([True,False,True,False,True])In [62]: arr=np.array([x if z else y for x,y,z in zip(arr1,arr2,arr3)])In [63]: arr Out[63]: array([ 1, -2, 3, -4, 5])In [64]: arr=np.array(np.where(arr3,arr1,arr2))#np.where返回的是數組In [65]: arr Out[65]: array([ 1, -2, 3, -4, 5])#將np.where用于替換值,如將數組的負數改為2:In [67]: arr=np.random.randn(10)In [68]: arr Out[68]: array([-0.43310012, -0.78072221, 0.05956466, 0.07686748, -0.29438555,-0.53863612, 0.96500903, -1.40994316, -1.03975959, 1.83357067])In [69]: arr_new=np.where(arr<0,2,arr)In [70]: arr_new Out[70]: array([2. , 2. , 0.05956466, 0.07686748, 2. ,2. , 0.96500903, 2. , 2. , 1.83357067])

數學和統計方法?

約簡

通過數組上的一組數學函數對整個數組或者某條軸上的數據進行統計計算,如求和sum、平均值mean以及標準差std等聚合計算(aggregation,通常叫做約簡(reduction))既可以當做數組的實例方法調用,也可以當做頂級Numpy函數使用

In [4]: arr=np.random.randn(5)#正態分布的隨即數據In [5]: arr Out[5]: array([-0.11860027, 1.05271905, 0.57255691, -0.49385782, 0.37800909])In [6]: arr.sum() Out[6]: 1.3908269625978642In [7]: np.sum(arr) Out[7]: 1.3908269625978642

mean和sum

這類函數可以接受一個axis參數,用于計算該軸向上的統計值,最終返回一個少一維的數組

In [9]: arr=np.arange(20).reshape(5,4)In [10]: arr Out[10]: array([[ 0, 1, 2, 3],[ 4, 5, 6, 7],[ 8, 9, 10, 11],[12, 13, 14, 15],[16, 17, 18, 19]])In [14]: arr.sum()#全部元素 Out[14]: 190In [15]: arr.sum(0)#在數組上一個列表表示一列,axis=0表示的是行,計算的是所有列表每個索引上的和 Out[15]: array([40, 45, 50, 55])In [16]: arr.sum(1)#數組上一個列表表示一列,axis=1表示的是列,計算的一個列表的和 Out[16]: array([ 6, 22, 38, 54, 70])

cumsum和cumprod

累計和,累計積這類方法則不聚合,而是產生一個由中間結果組成的數組

In [17]: arr Out[17]: array([[ 0, 1, 2, 3],[ 4, 5, 6, 7],[ 8, 9, 10, 11],[12, 13, 14, 15],[16, 17, 18, 19]])In [18]: arr.cumsum(axis=1)#列表內的累計和 Out[18]: array([[ 0, 1, 3, 6],[ 4, 9, 15, 22],[ 8, 17, 27, 38],[12, 25, 39, 54],[16, 33, 51, 70]])In [19]: arr.cumprod(axis=1)#列表內的累計積 Out[19]: array([[ 0, 0, 0, 0],[ 4, 20, 120, 840],[ 8, 72, 720, 7920],[ 12, 156, 2184, 32760],[ 16, 272, 4896, 93024]])

基本數組統計方法

sum全部或某軸向的元素求和,零長度的數組的sum為0
mean全部或某軸向的元素平均值,零長度的數組的mean為NaN
std、var

分別為標準差和方差,自由度可調(默認為n)

min、max全部或某軸向上的最大值和最小值
argmin、argmax全部或某軸向上的最大最小值的索引
cumsum全部或某軸向上的累計和
cumprod全部或某軸向上的累計積

用于布爾型數組的方法

在使用統計方法時,布爾值會強制轉換為1(True)和0(Flase),因此sum經常被用來對布爾型數組中True值的計數

In [28]: arr=np.random.randn(100)In [29]: (arr>0).sum() Out[29]: 52

any和all

any用于判斷存在一個或多個,all用于判斷全部都是

In [28]: arr=np.random.randn(100)In [30]: (arr>0).any() Out[30]: TrueIn [31]: (arr>0).all() Out[31]: False

排序sort

arr.sort和np.sort

通過arr.sort方法就地排序(直接改變源數據),np.sort()返回的是數組的已排序副本(即不修改源數據),可以對全部元素或者某軸向上的元素進行排序

In [46]: arr=np.random.randn(12).reshape(4,3)In [47]: arr Out[47]: array([[ 5.82831352e-02, -7.74374388e-01, 1.47850625e+00],[ 8.30603959e-01, -5.74236357e-01, -4.13521434e-01],[ 8.70914589e-04, -5.46720474e-01, -5.41121958e-01],[-7.03866197e-01, 1.95273830e+00, -5.85538385e-01]])In [48]: arr.sort()#默認axis=1,在列上排序In [49]: arr Out[49]: array([[-7.74374388e-01, 5.82831352e-02, 1.47850625e+00],[-5.74236357e-01, -4.13521434e-01, 8.30603959e-01],[-5.46720474e-01, -5.41121958e-01, 8.70914589e-04],[-7.03866197e-01, -5.85538385e-01, 1.95273830e+00]])In [50]: arr.sort(0)#行上排序,會改變列表的值In [51]: arr Out[51]: array([[-7.74374388e-01, -5.85538385e-01, 8.70914589e-04],[-7.03866197e-01, -5.41121958e-01, 8.30603959e-01],[-5.74236357e-01, -4.13521434e-01, 1.47850625e+00],[-5.46720474e-01, 5.82831352e-02, 1.95273830e+00]])

np.sort(arr)

In [52]: arr=np.random.randn(12).reshape(4,3)In [53]: arr Out[53]: array([[-1.0651435 , -0.70624382, 0.05124272],[ 0.69190929, 1.03548097, 0.64937742],[ 1.54626701, -0.08302486, 0.39043255],[-1.03014956, -0.12934306, 1.47813622]])In [54]: np.sort(arr) Out[54]: array([[-1.0651435 , -0.70624382, 0.05124272],[ 0.64937742, 0.69190929, 1.03548097],[-0.08302486, 0.39043255, 1.54626701],[-1.03014956, -0.12934306, 1.47813622]])In [55]: arr Out[55]: array([[-1.0651435 , -0.70624382, 0.05124272],[ 0.69190929, 1.03548097, 0.64937742],[ 1.54626701, -0.08302486, 0.39043255],[-1.03014956, -0.12934306, 1.47813622]])

唯一化和其他集合邏輯

np.unique

numpy提供了一些針對一維ndarray的基本集合運算,最常用的時np.unique,它用于找出數組中的唯一值并返回已排序的結果

In [61]: arr=np.array([1,1,2,3,4,5,2,3,4,5,6])In [62]: np.unique(arr) Out[62]: array([1, 2, 3, 4, 5, 6])

np.in1d

用于測試一個數組中的值在另一個數組中的成員資格,返回一個布爾型數組,第一個參數為源數據,驗證第二個參數在源數據中的成員資格

In [68]: arr1=np.array([1,2,3,4,5])In [69]: arr2=np.array([1,2,3,4,5,6])In [70]: np.in1d(arr1,arr2) Out[70]: array([ True, True, True, True, True])In [71]: np.in1d(arr1,[1,2...: ]) Out[71]: array([ True, True, False, False, False])

數組中的集合運算

unique()計算x中的唯一元素(去重),并返回有序結果
intersect1d(x,y)計算x,y的公共元素,并返回有序結果
union1d(x,y)

計算x,y的并集,并返回有序結果

in1d(x,y)得到一個表示'y元素是否在x中'的布爾型數組,數組長度等于x
setdiff1d(x,y)集合的差,即元素在x中且不在y中
setxor1d(x,y)集合的對稱差,即存在于一個數組中,但不同時存在于兩個數組中的元素,即'異或'

用于數組的文件輸入輸出

np.load和np.save, 用于讀寫磁盤數組數據,默認情況下,數組是以未壓縮的原始二進制格式保存在擴展名為.npy的文件中的

如果save的文件路徑末尾沒有擴展名.npy,則該擴展名會被自動加速,通過np.load讀取磁盤數據時需要加入后綴名

In [72]: arr=np.arange(10)In [73]: np.save('save_arr',arr) In [75]: np.load('save_arr.npy') Out[75]: array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])

np.savez

將多個數組保存到一個壓縮文件中,將數組以關鍵字參數的形式傳入即可,后綴名為.npz的文件,

加載.npz文件時,你會得到一個類似字典的對象,該對象會對各個數組進行延遲加載:

In [77]: np.savez('savez_arr',aaa=np.array([12,34]),bbb=np.array([3,4,2,2]))In [79]: np.load('savez_arr.npz') Out[79]: <numpy.lib.npyio.NpzFile at 0x7f321c1c7c50>In [80]: ar=np.load('savez_arr.npz')In [81]: ar['aaa'] Out[81]: array([12, 34])

np.loadtxt和np.genformtxt

將普通數據加載到普通的numpy的數組中,可以指定各種分隔符、針對特定列的轉換器函數、需要跳國的行數等

zelin@2018:~$ cat nppp.txt 1,1,1,1,1,1,1 2,2,2,2,2,2,2 3,3,3,3,3,3,3In [86]: np.loadtxt('nppp.txt',delimiter=',')#必須指定分隔符 Out[86]: array([[1., 1., 1., 1., 1., 1., 1.],[2., 2., 2., 2., 2., 2., 2.],[3., 3., 3., 3., 3., 3., 3.]])In [88]: np.genfromtxt('nppp.txt')#面向的時結構化數組和缺失數據處理 Out[88]: array([nan, nan, nan])

np.savetxt('filedir','data')將二維數組保存到txt文件中

In [94]: np.loadtxt('nppp.txt',delimiter=',').shape Out[94]: (3, 7)In [95]: np.savetxt('ssss.txt',np.loadtxt('nppp.txt',delimiter=','))zelin@2018:~$ cat ssss.txt 1.000000000000000000e+00 1.000000000000000000e+00 1.000000000000000000e+00 1.000000000000000000e+00 1.000000000000000000e+00 1.000000000000000000e+00 1.000000000000000000e+00 2.000000000000000000e+00 2.000000000000000000e+00 2.000000000000000000e+00 2.000000000000000000e+00 2.000000000000000000e+00 2.000000000000000000e+00 2.000000000000000000e+00 3.000000000000000000e+00 3.000000000000000000e+00 3.000000000000000000e+00 3.000000000000000000e+00 3.000000000000000000e+00 3.000000000000000000e+00 3.000000000000000000e+00

線性代數

np.dot(x,y)和x.dot(y)得到的結果一樣

如矩陣乘法、矩陣分解、行列式以及其他方陣數學,numpt提供了一個用于矩陣乘法的dot函數(既是一個數組方法也是numpy命名空間中的一個函數)

In [96]: x=np.array([[1,2,3],[4,5,6]])In [97]: y=np.array([[7,8],[9,11],[12,13]])In [98]: np.dot(x,y) Out[98]: array([[ 61, 69],[145, 165]])In [99]: x.dot(y) Out[99]: array([[ 61, 69],[145, 165]])

一個二維數組跟一個大小合適的一維數組的矩陣點積運算之后將會得到一個一維數組:

In [100]: x=np.array([[1,2,3],[4,5,6]])In [101]: y=np.array([1,2,3])In [102]: x.dot(y) Out[102]: array([14, 32])

numpy.linalg

linalg中由一組標準矩陣分解運算以及諸如求逆和行列式之類的東西

In [126]: x=np.random.randn(5,5)In [127]: mat=x.T.dot(x)In [128]: inv(mat)#計算乘法的逆 Out[128]: array([[ 383.46895288, 440.98999139, 149.94498526, -163.43061669,-297.78805292],[ 440.98999139, 507.78623867, 172.63437908, -188.1462194 ,-343.09305341],[ 149.94498526, 172.63437908, 59.30910465, -64.09383187,-116.02238766],[-163.43061669, -188.1462194 , -64.09383187, 69.91440892,126.83237131],[-297.78805292, -343.09305341, -116.02238766, 126.83237131,233.04712006]])In [129]: mat.dot(inv(mat))#計算矩陣的qr分解 Out[129]: array([[ 1.00000000e+00, 5.68434189e-14, -1.27897692e-13,2.84217094e-14, 0.00000000e+00],[ 0.00000000e+00, 1.00000000e+00, 5.68434189e-14,-1.13686838e-13, 0.00000000e+00],[ 1.13686838e-13, -1.13686838e-13, 1.00000000e+00,5.68434189e-14, 0.00000000e+00],[-3.41060513e-13, -2.27373675e-13, 0.00000000e+00,1.00000000e+00, 2.27373675e-13],[-2.27373675e-13, -1.13686838e-13, -5.68434189e-14,1.13686838e-13, 1.00000000e+00]])In [130]: q,r=qr(mat)In [131]: q Out[131]: array([[-0.63453898, -0.47094923, 0.18141456, 0.19269952, -0.55274112],[ 0.7372586 , -0.20651792, 0.0060628 , 0.09058399, -0.63683428],[-0.14374066, 0.32326252, -0.7934532 , 0.44597525, -0.21535567],[ 0.05296628, -0.70849705, -0.56096271, -0.35372934, 0.23542068],[ 0.1741931 , -0.35929159, 0.15101276, 0.79413038, 0.43257184]])In [132]: r Out[132]: array([[-3.51536372e+00, 8.37098488e+00, -3.43363927e+00,4.29370726e+00, 3.78639110e+00],[ 0.00000000e+00, -5.77553574e+00, 2.53098177e+00,-7.12560115e+00, -3.36626363e+00],[ 0.00000000e+00, 0.00000000e+00, -2.65421554e+00,-3.56576864e+00, 6.19863832e-01],[ 0.00000000e+00, 0.00000000e+00, 0.00000000e+00,-8.85238991e-01, 4.85185531e-01],[ 0.00000000e+00, 0.00000000e+00, 0.00000000e+00,0.00000000e+00, 1.85615613e-03]])

常用的numpy.linalg函數

diag以一維數組的形式返回方針的對角線元素,或將一維數組轉換為方陣
dot矩陣乘法
trace計算對角線元素的和
det計算矩陣行列式
eig計算方陣的本征值和本征向量
inv計算方陣的逆
pinv計算矩陣的Moor-Penrose偽逆
qr計算QR分解
svd計算奇異值分解
solve解線性方程組Ax=b,其中A為一個方陣
lstsq計算
??
??
??
??
??
??
??

隨機數生成

numpy.random模塊對python內置的random進行了補充,增加了一些用于高效生成多種嗯概率分布的樣本值的函數,例如,用normal來得到一個標準正太分布的4*4樣本數組

In [133]: samples=np.random.normal((4,4))#與關鍵字參數不同In [134]: samples Out[134]: array([3.57761124, 2.31337006])In [135]: samples=np.random.normal(size=(4,4))In [136]: samples Out[136]: array([[ 0.78330662, -0.56505952, -0.97143979, -0.33209158],[-0.34771653, -0.30901418, -0.53225815, -0.08778485],[-1.0037474 , 0.87408366, -0.98363945, 0.5701133 ],[-1.42551243, 0.12037672, -0.49017895, 0.65434629]])

python內置的random模塊只能一次生成一個樣本值,如果需要產生大量樣本值,numpy.random快了不只一個數量級

部分numpy.random函數

seed確定隨機數生成器的種子
permutation返回一個序列的隨即排列或返回一個隨即排列的范圍
shuffle對一個序列就地隨即排列
rand產生均勻分布的樣本值
randint從給定的上下限范圍內隨即選區整數
randn產生正態分布(平均值為0,標準差為1)的樣本值
binomial產生二項分布的樣本值
normal產生正太(高斯)分布的樣本值
beta產生beta分布的樣本值
chisquare產生卡方分布的樣本值
gamma產生gamma分布的樣本值
uniform產生在[1,0)中均勻分布的樣本值
??

隨機漫步

In [136]: import random In [137]: position=0In [138]: walk=[position]In [139]: steps=1000 #純python方法 In [178]: for i in range(steps):...: step=1 if random.randint(0,2) else -1...: position+=step...: walk.append(position) #numpy方法 In [180]: nsteps=1000In [181]: draws=np.random.randint(0,2,size=nsteps)In [182]: steps=np.where(draws,1,-1)In [183]: walk=np.cumsum(steps)In [184]: walk

一次模擬多個隨即漫步

只要給numpy.random的函數傳入一個二元元組就可以產生一個二維數組,然后我們就可以一次性計算5000個隨即漫步過程(一行一個)的累計和了

In [185]: nsteps=5000In [186]: draws=np.random.randint(0,2,(10,500))#10行500列In [187]: walk=np.where(draws,1,-1)In [188]: np.cumsum(walk) Out[188]: array([ 1, 0, 1, ..., -60, -59, -60]) In [190]: walks.max() Out[190]: 33In [191]: walks.min() Out[191]: -75

?

數組重塑

reshape

In [15]: arr Out[15]: array([0, 1, 2, 3, 4, 5, 6, 7])In [16]: arr.reshape((4,2)) Out[16]: array([[0, 1],[2, 3],[4, 5],[6, 7]]) #多維數組也可以重塑 In [17]: arr.reshape((4,2)).reshape(2,4) Out[17]: array([[0, 1, 2, 3],[4, 5, 6, 7]]) #作為參數的形狀的其中一維可以是-1,表示該維度的大小由數據本身推斷而來 In [21]: arr.reshape((5,-1)) Out[21]: array([[ 0, 1, 2],[ 3, 4, 5],[ 6, 7, 8],[ 9, 10, 11],[12, 13, 14]])In [22]: arr.reshape((3,-1)) Out[22]: array([[ 0, 1, 2, 3, 4],[ 5, 6, 7, 8, 9],[10, 11, 12, 13, 14]])#由于數組的形狀(shape)也是一個元組,因此它可以被傳入reshape: In [33]: arr1=np.ones((3,4))In [34]: arr2=np.ones((12))In [35]: arr1 Out[35]: array([[1., 1., 1., 1.],[1., 1., 1., 1.],[1., 1., 1., 1.]])In [36]: arr2 Out[36]: array([1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1.])In [37]: s=arr1.shapeIn [38]: arr2.reshape(s) Out[38]: array([[1., 1., 1., 1.],[1., 1., 1., 1.],[1., 1., 1., 1.]])

扁平化或散開

與reshape將一維數組轉換為多維數組的運算過程相反的運算通常稱為扁平化或散開

ravel()和flatten()

功能類似,但ravel不會產生源數據的副本,flatten方法返回的是源數據的副本

In [39]: arr=np.arange(15).reshape((3,5))In [40]: arr Out[40]: array([[ 0, 1, 2, 3, 4],[ 5, 6, 7, 8, 9],[10, 11, 12, 13, 14]])In [41]: arr.ravel() Out[41]: array([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14])In [42]: arr Out[42]: array([[ 0, 1, 2, 3, 4],[ 5, 6, 7, 8, 9],[10, 11, 12, 13, 14]])In [43]: arr.flatten() Out[43]: array([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14])In [44]: arr Out[44]: array([[ 0, 1, 2, 3, 4],[ 5, 6, 7, 8, 9],[10, 11, 12, 13, 14]])

C和Fortran順序

默認情況下,Numpy數組是按行優先順序創建的,在空間方面,這意味著,對于一個二維數組,每行中的數據項是被存放在相鄰內存位置上的,另一種順序是列優先順序,它意味著美列中的數據項是被存放在相鄰位置上的。

行優先稱為C順序,列優先稱為Fortran順序,像reshape,reval這樣的函數,都可以接受一個表示數組數據存放順序的order參數,一般可以是‘C’或‘F’,得到不同的數組

二維數組重塑過程,C和Fortran順序的關鍵區別就是維度的行進順序

C順序:先經過更高的維度,如軸1會優先于軸0被處理

Forttran順序:后經過更高的維度,如軸0會優先于軸1被處理

In [46]: arr Out[46]: array([[ 0, 1, 2, 3],[ 4, 5, 6, 7],[ 8, 9, 10, 11]])In [47]: arr.ravel()#默認行優先 Out[47]: array([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11])In [48]: arr.ravel(order='C')#顯式行優先 Out[48]: array([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11])In [49]: arr.ravel(order='F')#列優先 Out[49]: array([ 0, 4, 8, 1, 5, 9, 2, 6, 10, 3, 7, 11])

數組的合并與拆分

concatenate()

可以按指定軸將一個由數組組成的序列(如列表,元組等)連接到一起

In [51]: arr=np.array([[1,2,3],[4,5,6]])In [52]: arr1=np.array([[7,8,9],[10,11,12]])In [53]: np.concatenate([arr,arr1],axis=0) Out[53]: array([[ 1, 2, 3],[ 4, 5, 6],[ 7, 8, 9],[10, 11, 12]])In [54]: np.concatenate([arr,arr1],axis=1) Out[54]: array([[ 1, 2, 3, 7, 8, 9],[ 4, 5, 6, 10, 11, 12]])

vstack()和hstack()

對與常見的連接操作,也可以使用Numpy提供的vstack和hstack函數

In [56]: np.vstack((arr,arr1))#axis=0 Out[56]: array([[ 1, 2, 3],[ 4, 5, 6],[ 7, 8, 9],[10, 11, 12]])In [57]: np.hstack((arr,arr1))#axis=1 Out[57]: array([[ 1, 2, 3, 7, 8, 9],[ 4, 5, 6, 10, 11, 12]])

split()

split用于將一個數組沿指定軸拆分為多個數組

In [61]: arr=np.random.randn(5,2)In [62]: arr Out[62]: array([[-0.82230236, 0.62723821],[ 2.18883671, -0.27052682],[-0.45726504, -1.66183692],[-0.42266318, 0.84994138],[-0.30175674, 1.25396072]])In [63]: first,second,third=np.split(arr,[1,3])In [64]: first Out[64]: array([[-0.82230236, 0.62723821]])#半開放區間,邊界軸在下一個數組分區In [65]: second Out[65]: array([[ 2.18883671, -0.27052682],[-0.45726504, -1.66183692]])In [66]: third Out[66]: array([[-0.42266318, 0.84994138],[-0.30175674, 1.25396072]])

堆疊輔助類:r_和c_

使數組的堆疊操作更為簡潔

In [77]: arr=np.arange(6)In [78]: arr1=arr.reshape((3,2))In [79]: arr2=np.random.randn(3,2)In [80]: np.r_[arr1,arr2]#增加行 Out[80]: array([[ 0. , 1. ],[ 2. , 3. ],[ 4. , 5. ],[ 0.19138704, -1.34381651],[-2.13175216, -1.28283516],[-1.79236481, 0.11647346]])In [81]: np.c_[np.r_[arr1,arr2],arr]#增加列 Out[81]: array([[ 0. , 1. , 0. ],[ 2. , 3. , 1. ],[ 4. , 5. , 2. ],[ 0.19138704, -1.34381651, 3. ],[-2.13175216, -1.28283516, 4. ],[-1.79236481, 0.11647346, 5. ]])In [82]: np.c_[1:6,-10:-5]#生成數組 Out[82]: array([[ 1, -10],[ 2, -9],[ 3, -8],[ 4, -7],[ 5, -6]])

元素的重復操作:tile和repeat

對數組進行重復以產生更大數組的工具主要是repeat和tile這兩個函數,repeat會將數組中的各個元素重復一定次數,從而產生一個更大的數組

In [84]: arr=np.array([1,2,3])In [85]: arr.repeat(3) Out[85]: array([1, 1, 1, 2, 2, 2, 3, 3, 3]) #默認情況下,如果傳入的是一個整數,則各元素都會重復整數次,如果傳入一組整數(元組形式),則各元素就可以重復不同的次數 In [88]: arr.repeat((3,2,3))#元組長度需要與數組列數相同 Out[88]: array([1, 1, 1, 2, 2, 3, 3, 3]) #多維數組可以沿指定軸重復 In [92]: arr=np.random.randn(4,5)In [93]: arr.repeat((1,2,3,4),axis=0)#按行重復 Out[93]: array([[ 0.1374145 , -0.17461463, -0.3860606 , 0.37310723, -0.33203066],[-0.94992704, -0.21039861, -0.46802276, 2.23576964, -0.01360194],[-0.94992704, -0.21039861, -0.46802276, 2.23576964, -0.01360194],[-1.10704975, 2.15029587, 1.06162111, -0.76405616, -0.01180898],[-1.10704975, 2.15029587, 1.06162111, -0.76405616, -0.01180898],[-1.10704975, 2.15029587, 1.06162111, -0.76405616, -0.01180898],[ 1.39670354, 0.45674728, 1.4260907 , 2.22409618, 0.61247909],[ 1.39670354, 0.45674728, 1.4260907 , 2.22409618, 0.61247909],[ 1.39670354, 0.45674728, 1.4260907 , 2.22409618, 0.61247909],[ 1.39670354, 0.45674728, 1.4260907 , 2.22409618, 0.61247909]])In [95]: arr.repeat((1,2,3,4,5),axis=1)#按列重復,即重復元素 Out[95]: array([[ 0.1374145 , -0.17461463, -0.17461463, -0.3860606 , -0.3860606 ,-0.3860606 , 0.37310723, 0.37310723, 0.37310723, 0.37310723,-0.33203066, -0.33203066, -0.33203066, -0.33203066, -0.33203066],[-0.94992704, -0.21039861, -0.21039861, -0.46802276, -0.46802276,-0.46802276, 2.23576964, 2.23576964, 2.23576964, 2.23576964,-0.01360194, -0.01360194, -0.01360194, -0.01360194, -0.01360194],[-1.10704975, 2.15029587, 2.15029587, 1.06162111, 1.06162111,1.06162111, -0.76405616, -0.76405616, -0.76405616, -0.76405616,-0.01180898, -0.01180898, -0.01180898, -0.01180898, -0.01180898],[ 1.39670354, 0.45674728, 0.45674728, 1.4260907 , 1.4260907 ,1.4260907 , 2.22409618, 2.22409618, 2.22409618, 2.22409618,0.61247909, 0.61247909, 0.61247909, 0.61247909, 0.61247909]])

tile是沿指定軸向堆疊數組的副本,可以將其想象成'鋪瓷磚',

第二參數表示瓷磚的數量,對于標量,瓷磚是水平鋪設的,而不是垂直鋪設,可以傳入一個表示鋪設布局的元組

In [96]: arr=np.random.randn(2,2)In [98]: np.tile(arr,2)#堆疊數組的副本,默認堆疊元素 Out[98]: array([[ 0.42442511, 0.61368951, 0.42442511, 0.61368951],[ 0.25196689, -0.54785916, 0.25196689, -0.54785916]])In [99]: np.tile(arr,(2,1))#堆疊行 Out[99]: array([[ 0.42442511, 0.61368951],[ 0.25196689, -0.54785916],[ 0.42442511, 0.61368951],[ 0.25196689, -0.54785916]])In [100]: np.tile(arr,(2,3))#堆疊行2,堆疊列(元素)3 Out[100]: array([[ 0.42442511, 0.61368951, 0.42442511, 0.61368951, 0.42442511,0.61368951],[ 0.25196689, -0.54785916, 0.25196689, -0.54785916, 0.25196689,-0.54785916],[ 0.42442511, 0.61368951, 0.42442511, 0.61368951, 0.42442511,0.61368951],[ 0.25196689, -0.54785916, 0.25196689, -0.54785916, 0.25196689,-0.54785916]])

花式索引的等價函數:take和put

獲取和設置數組子集的一個辦法是通過整數數組使用花式索引:

In [105]: arr=np.arange(10)*100In [106]: arr[[7,2,1,3]] Out[106]: array([700, 200, 100, 300])

ndarray有兩個方法專門用于獲取和設置單個軸向上的選區:

take 是花式索引的等價函數,行/列上的參數為axis=0或axis=1

put 是將花式索引表達的元素進行替換,put不支持axis參數,只能在數組的扁平化版本(一維,C順序)上進行索引

最好的選擇還是直接使用花式索引,而不是函數

In [107]: arr=np.arange(10)*100In [108]: arr.take([7,1,2,6])#花式索引的等價函數 Out[108]: array([700, 100, 200, 600])In [109]: arr.put([7,1,2,6],42)#花式索引值替換In [110]: arr Out[110]: array([ 0, 42, 42, 300, 400, 500, 42, 42, 800, 900])In [111]: arr.put([7,1,2,6],[11,22,33,44,55])#傳如入一個等長列表,同步替換In [112]: arr Out[112]: array([ 0, 22, 33, 300, 400, 500, 44, 11, 800, 900])

廣播

廣播(broadcasting)指的是不同形狀的數組之間的算術運算的執行方式,將標量值跟數組合并就會發生最簡單的廣播,即標量值被廣播到了數組的所有元素上,不同形狀指的是行數不同,列數相同才能進行廣播。(廣播的原則:如果兩個數組的后緣維度(trailing dimension ,即從末尾開始計算起的維度)的軸長度相符或其中一方的長度為1,則認為他們是廣播兼容的,廣播會在缺失和1長度為1的維度上進行)

距平化:即系列數值與其平均值的差

In [120]: arr=np.random.randn(4,3)In [121]: arr.mean(0) Out[121]: array([-0.07543098, 0.83298458, -0.02126994])In [122]: arr-arr.mean(0)#由于mean(0)的長度正好為3,所以可以直接相減 Out[122]: array([[-0.27645797, 1.38328286, -1.22593655],[ 1.59969598, -0.03434764, 1.62403164],[-1.03478433, 0.31967476, 0.14974559],[-0.28845368, -1.66860997, -0.54784068]]) #由于arr.mean(0)的長度為3,所以可以直接在0軸上進行廣播,因為mean(0)的后緣長度為3,所以他們是兼容的,根據廣播原則,要在1軸上作減法,則較小的那個數組形狀必須是(4,1),其中行必須是4 In [133]: res=arr.mean(1).reshape((4,1))In [134]: res Out[134]: array([[ 0.19789142],[-0.19232197],[-0.64339871],[ 0.14236788]])In [135]: arr-res Out[135]: array([[-0.90398182, 0.37917518, 0.52480664],[-0.23696029, -0.24588066, 0.48284096],[ 0.01379453, -0.22597313, 0.21217861],[-0.28368762, 0.34259934, -0.05891172]])

三維數組的廣播

高緯度數組的廣播也是遵循廣播原則的。人們經常通過算術運算過程將較低維度的數組在0軸以外的其他軸向上廣播,根據廣播原則,較小數組的'廣播維'必須是1,所以在進行距平化的廣播中,較小的數組形狀必須是(N,1),不能是(N,),雖然他們表達數組視圖是相同的

下圖簡單說明了能在三維數組上廣播的二維數組

np.newaxis屬性以及'全'切片

對于三維數組,在三維中的任何一維上廣播其實也是將數據重塑為兼容的形狀而已,于是就有一個非常普遍的操作,即專門為了廣播而添加一個長度為1的新軸,Numpy數組提供了一種通過索引機制插入軸的特殊語法

In [144]: arr=np.zeros((4,4))In [145]: arr_3d=arr[:,np.newaxis,:]In [146]: arr_3d.shape Out[146]: (4, 1, 4)In [147]: arr_1d=np.random.normal(size=3)In [148]: arr_1d Out[148]: array([ 0.95908759, 0.67838227, -1.21728343])In [149]: arr_1d[:,np.newaxis] Out[149]: array([[ 0.95908759],[ 0.67838227],[-1.21728343]])In [150]: arr_1d[np.newaxis,:] Out[150]: array([[ 0.95908759, 0.67838227, -1.21728343]])

假設我們有一個三維數組,需要在軸2上進行距平化

In [153]: arr=np.random.randn(3,4,5)In [154]: arr Out[154]: array([[[ 0.28431603, 0.44861501, -0.20777097, 0.28023136,0.17530054],[ 0.55700422, -0.14012566, 0.18500479, 1.04806987,-0.9508947 ],[-0.18838964, 0.04586741, 0.84066257, -0.07401783,1.46106524],[-0.15170269, -1.36097563, 0.59832985, 0.45333389,1.66786734]],[[-1.17441825, -0.00574066, 0.26356278, 0.82866366,-0.76109032],[ 0.10570107, -1.15842887, 0.43370703, -0.56219272,1.90148085],[-1.24608118, -0.54931805, -0.91075277, 0.21715073,0.59751696],[ 0.3297414 , -1.10564384, -0.54772233, -1.59229321,0.19203631]],[[ 2.03384505, 0.17328362, 1.59381343, 1.11969745,-0.62698893],[ 1.02854294, -0.97755266, 0.0048308 , -0.70172524,-0.12799296],[-0.42962065, 0.05177602, 0.18382527, -0.6816369 ,0.75557744],[ 0.19051328, -0.82344915, 0.90430084, 1.30163513,-0.61083626]]])In [155]: depth_means=arr.mean(2)In [156]: depth_means Out[156]: array([[ 0.19613839, 0.1398117 , 0.41703755, 0.24137055],[-0.16980456, 0.14405347, -0.37829686, -0.54477633],[ 0.85873013, -0.15477942, -0.02401576, 0.19243277]])In [157]: depth_means.shape Out[157]: (3, 4)In [158]: demeaned=arr-depth_means[:,:,np.newaxis]In [159]: demeaned Out[159]: array([[[ 0.08817763, 0.25247662, -0.40390936, 0.08409296,-0.02083785],[ 0.41719252, -0.27993736, 0.04519309, 0.90825817,-1.09070641],[-0.60542719, -0.37117014, 0.42362502, -0.49105538,1.04402769],[-0.39307324, -1.60234618, 0.35695929, 0.21196334,1.42649679]],[[-1.00461369, 0.1640639 , 0.43336734, 0.99846822,-0.59128577],[-0.03835241, -1.30248234, 0.28965356, -0.7062462 ,1.75742738],[-0.86778431, -0.17102119, -0.53245591, 0.59544759,0.97581382],[ 0.87451774, -0.56086751, -0.002946 , -1.04751687,0.73681264]],[[ 1.17511493, -0.6854465 , 0.7350833 , 0.26096733,-1.48571906],[ 1.18332236, -0.82277324, 0.15961023, -0.54694581,0.02678646],[-0.40560488, 0.07579178, 0.20784104, -0.65762114,0.7795932 ],[-0.00191949, -1.01588192, 0.71186807, 1.10920236,-0.80326902]]])In [161]: d=depth_means[:,:,np.newaxis]In [162]: d.shape Out[162]: (3, 4, 1)

通過廣播設置數組的值

算術運算所遵循的廣播原則同樣也適用于通過索引機制設置數組值的操作,假設我們用一個一維數組來設置目標數組的各列,只要保證兼容就可以了

In [168]: col=np.array([1.12,-0.43,0.44,1.6])In [169]: arr=np.zeros((4,3))In [170]: arr[:]=col[:,np.newaxis]In [171]: arr Out[171]: array([[ 1.12, 1.12, 1.12],[-0.43, -0.43, -0.43],[ 0.44, 0.44, 0.44],[ 1.6 , 1.6 , 1.6 ]])In [172]: arr[:2]=[[222],[333]]In [173]: arr Out[173]: array([[222. , 222. , 222. ],[333. , 333. , 333. ],[ 0.44, 0.44, 0.44],[ 1.6 , 1.6 , 1.6 ]])

ufunc高級應用

ufunc(universal function)是指能夠應用到ndarray對象的每一個元素上,而不僅僅是ndarray對象

reduce接受一個數組參數,并通過一系列的二元運算對其值進行聚合(可指名軸向)

In [174]: arr=np.arange(10)In [175]: np.add.reduce(arr) Out[175]: 45In [176]: arr.sum() Out[176]: 45

np.logical_and用于檢查數組各行中的值是否是有序的,

In [177]: arr=np.random.randn(5,5)In [178]: arr[::2].sort(1)#對部分行進行排序In [179]: arr[:,:-1]<arr[:,1:] Out[179]: array([[ True, True, True, True],[False, True, True, True],[ True, True, True, True],[False, True, False, False],[ True, True, True, True]]) #np.logical_and.reduce和all方法是等價的 In [180]: np.logical_and.reduce(arr[:,:-1]<arr[:,1:],axis=1) Out[180]: array([ True, False, True, False, True])

accumulate跟reduce的關系就像cumsum和sum的關系一樣,它產生一個跟原數組大小相同的中間'累計'值數組

In [181]: arr=np.arange(15).reshape(3,5)In [182]: np.add.accumulate(arr,axis=1) Out[182]: array([[ 0, 1, 3, 6, 10],[ 5, 11, 18, 26, 35],[10, 21, 33, 46, 60]])

outer用于計算兩個數組的叉積,outer輸出結果的維度是兩個輸入數據的維度之和

In [183]: arr=np.arange(3).repeat([1,2,3])In [184]: arr Out[184]: array([0, 1, 1, 2, 2, 2])In [186]: np.multiply.outer(arr,np.arange(5)) Out[186]: array([[0, 0, 0, 0, 0],[0, 1, 2, 3, 4],[0, 1, 2, 3, 4],[0, 2, 4, 6, 8],[0, 2, 4, 6, 8],[0, 2, 4, 6, 8]])#維度 In [187]: res=np.subtract.outer(np.random.randn(4,5),np.random.randn(5))In [188]: res.shape Out[188]: (4, 5, 5)

reduceat用于計算'局部約簡',其實就是一個對數據各切片進行聚合的groupby運算,雖然其靈活性不如pandas的groupby功能,但適當的情況下運算會非常快,它接受一組用于指示如何對值進行拆分和聚合的'面元邊界'

In [189]: arr=np.arange(10)In [190]: np.add.reduceat(arr,[0,5,8]) Out[190]: array([10, 18, 17]) #其最終結果是在arr[0:5],arr[5:8]和arr[8:]上執行約簡(本例中就是求和),和其他方法億元,也可傳入一個axis參數 In [191]: arr=np.multiply.outer(np.arange(4),np.arange(5))In [192]: arr Out[192]: array([[ 0, 0, 0, 0, 0],[ 0, 1, 2, 3, 4],[ 0, 2, 4, 6, 8],[ 0, 3, 6, 9, 12]])In [193]: np.add.reduceat(arr,[0,2,4],axis=1) Out[193]: array([[ 0, 0, 0],[ 1, 5, 4],[ 2, 10, 8],[ 3, 15, 12]])

自定義ufunc

使自定義的函數能夠像ufunc一樣使用

frompyfunc和vectorize

numpy.frompyfunc接受一個python函數以及兩個分別表示輸入輸出參數數量的整數,使用frompyfunc創建的自定義ufunc只能返回一個python對象數組,numpy.vectorize則返回一個數組對象。

雖然這兩個函數提供了一種創建ufunc型函數的手段,但他們非常曼,因為他們在計算每個元素的時候都要執行一次python函數調用,比numpy基于C的ufunc慢很多

In [194]: def add_element(x,y):...: return x+y...: In [195]: add_them=np.frompyfunc(add_element,2,1)In [196]: add_them(np.arange(8),np.arange(8)) Out[196]: array([0, 2, 4, 6, 8, 10, 12, 14], dtype=object)#vectorize返回一個數組對象 In [197]: add_them2=np.vectorize(add_element,otypes=[np.float64])In [198]: add_them2(np.arange(8),np.arange(8)) Out[198]: array([ 0., 2., 4., 6., 8., 10., 12., 14.])

結構化和記錄式數組

ndarray是一種同質數據容器,也就是說它所表示的內存塊中,各元素所占用的字節數相同(具體數根據dtype而定),

結構化數組是一種特殊的ndarray,其中各個元素可以被看作C語言中的結構體(struct,這就是‘結構化'的由來)或SQL表中帶有多個命名字段的行

跟pandas的DataFrame相比,結構化數組是一種相對較低級的工具,它可以將單個內存塊解釋為代有任意復雜嵌套列的表格型結構,由于數組中的每個元素在內存中都被表示為固定的字節數,所以結構化數組能夠提供翡翠快速高效的的磁盤數據讀寫、網絡傳輸等功能

結構化數組的另一個用法是將數據文件寫成定長記錄字節流,只要知道文件的格式(記錄的大小、元素的順序、字節數以及數據類型),就可以用np.fromfile將數據讀入內存---了解即可

numpy.lib.recfunctions模塊可用于操作結構化數組--了解即可

In [199]: dtype=[('x',np.float64),('y',np.int32)]In [200]: sarr=np.array([(1.5,6),(np.pi,-2)],dtype=dtype)#np.pi 圓周率In [201]: sarr Out[201]: array([(1.5 , 6), (3.14159265, -2)],dtype=[('x', '<f8'), ('y', '<i4')])#定義結構化dtype最典型的辦法是元組列表,各元組的格式為(field_name,field_data_type),這樣,數組的元素就成了元組式的對象,該對象中各個元素可以向字典那樣進行訪問 In [202]: sarr[0] Out[202]: (1.5, 6)In [203]: sarr[1] Out[203]: (3.14159265, -2)In [204]: sarr[2] --------------------------------------------------------------------------- IndexError Traceback (most recent call last) <ipython-input-204-d3424412ab64> in <module>() ----> 1 sarr[2]IndexError: index 2 is out of bounds for axis 0 with size 2In [205]: sarr[0]['x'] Out[205]: 1.5In [206]: sarr[0]['y'] Out[206]: 6In [207]: sarr['y'] Out[207]: array([ 6, -2], dtype=int32) #字段名保存在dtype.name屬性中,在訪問結構化數組在的某個字段時,返回的是該數據的視圖,所以不會發生數據復制

嵌套dtype和多維字段

在定義結構化dtype時,可以再設置一個形狀(可以是個整數,也可以是一個元組)

In [208]: dtype=[('x',np.float64,3),('',np.int32)]In [209]: arr=np.zeros(4,dtype=dtype)In [210]: arr Out[210]: array([([0., 0., 0.], 0), ([0., 0., 0.], 0), ([0., 0., 0.], 0),([0., 0., 0.], 0)], dtype=[('x', '<f8', (3,)), ('f1', '<i4')]) #各個記錄的x字段所表示的是一個長度為3的數組 In [211]: arr[0] Out[211]: ([0., 0., 0.], 0)In [212]: arr[0]['x'] Out[212]: array([0., 0., 0.]) #訪問arr['x']得到一個二維數組,而不是前面的一維數組 In [213]: arr['x'] Out[213]: array([[0., 0., 0.],[0., 0., 0.],[0., 0., 0.],[0., 0., 0.]])

這使我們能夠用單個數組的內存塊存放復雜的數據結構,既然dtype可以想怎么復雜就怎么復雜,我們可以試試嵌套dtype,與此相比,pandas的分層索引機制跟這個差不多

In [214]: dtype=[('x',[('a','f8'),('b','f4')]),('y',np.int32)]In [215]: data=np.array([((1,2),5),((3,4),6)],dtype=dtype)In [216]: data['x'] Out[216]: array([(1., 2.), (3., 4.)], dtype=[('a', '<f8'), ('b', '<f4')])In [217]: data['y'] Out[217]: array([5, 6], dtype=int32)In [218]: data['x']['a'] Out[218]: array([1., 3.])

排序

跟python內置的列表一樣,ndarray的sort實例方法也是就地排序,即,數組內容的重新排序是在源數組上排序的,不會產生新數組的,如果排序的目標數組只是一個視圖,則源數組將會被修改

In [219]: arr=np.random.randn(6)In [220]: arr Out[220]: array([ 0.44345783, -0.67660014, 0.13668712, -0.04890943, -0.83586259,0.61457904])In [221]: arr.sort()In [222]: arr Out[222]: array([-0.83586259, -0.67660014, -0.04890943, 0.13668712, 0.44345783,0.61457904]) #切片排序也會影響源數組 In [226]: arr=np.random.randn(6)In [227]: arr Out[227]: array([ 1.3510239 , -0.42457162, 0.70866059, -0.07718412, 1.0291165 ,1.26459721])In [228]: arr[:5].sort()In [229]: arr Out[229]: array([-0.42457162, -0.07718412, 0.70866059, 1.0291165 , 1.3510239 ,1.26459721])

numpy.sort會為源數組創建一個已排序副本,它接收一個數組作為參數

In [230]: arr=np.random.randn(6)In [231]: arr Out[231]: array([-0.58542925, 1.35982495, -0.80136903, -0.22464326, -0.48581381,-0.98496352])In [232]: np.sort(arr) Out[232]: array([-0.98496352, -0.80136903, -0.58542925, -0.48581381, -0.22464326,1.35982495])

ndarray.sort和np.sort(ndarray)兩個排序方法都可以接受一個axis參數,以便沿指定軸向對各塊數據進行單獨排序

In [233]: arr=np.random.randn(3,5)In [234]: arr Out[234]: array([[-1.01999619, 0.73470564, -0.38008688, -1.07978726, 1.5174322 ],[-0.45355041, 0.07185554, -1.97314749, 0.00603521, 0.05596924],[-1.63445938, -0.49933928, -1.11881907, 0.03452264, 0.97180303]])In [235]: arr.sort(axis=1)In [236]: arr Out[236]: array([[-1.07978726, -1.01999619, -0.38008688, 0.73470564, 1.5174322 ],[-1.97314749, -0.45355041, 0.00603521, 0.05596924, 0.07185554],[-1.63445938, -1.11881907, -0.49933928, 0.03452264, 0.97180303]])In [237]: arr.sort(axis=0)In [238]: arr Out[238]: array([[-1.97314749, -1.11881907, -0.49933928, 0.03452264, 0.07185554],[-1.63445938, -1.01999619, -0.38008688, 0.05596924, 0.97180303],[-1.07978726, -0.45355041, 0.00603521, 0.73470564, 1.5174322 ]])

ndarray.sort()和np.sort(ndarray)兩種方法都不支持降序排列,需要在排序后使用[::-1]返回一個反序的列表

In [239]: arr=np.arange(6)In [240]: arr Out[240]: array([0, 1, 2, 3, 4, 5])In [241]: arr[::-1] Out[241]: array([5, 4, 3, 2, 1, 0])

間接排序:argsort和lexsort

在數據分析工作中,常常需要根據一個或多個鍵對數據集進行排序,例如,一個有關學生信息的數據表可能需要以姓和名進行排序,這就是間接排序

給定一個或多個鍵,可以得到一個由整數組成的索引數組(稱之為索引器),其中索引值說明了數據在新順序下的位置

argsort和lexsort就是實現該功能的兩個主要方法,pandas對象Series和DateFrame的sortindex以及Series的order方法就是通過這些函數的變體實現的(pandas對象需要考慮缺失值)

In [242]: values=np.array([5,0,1,3,2])In [243]: indexer=values.argsort()In [244]: indexer Out[244]: array([1, 2, 4, 3, 0])In [245]: values[indexer] Out[245]: array([0, 1, 2, 3, 5]) #根據數組的第一行對其進行排序 In [246]: arr=np.random.randn(3,5)In [247]: arr[0]=valuesIn [248]: arr Out[248]: array([[ 5. , 0. , 1. , 3. , 2. ],[-0.62471185, 0.25591603, 0.28292862, -0.02259515, -2.22019292],[-1.29263396, 0.61927654, 0.66283367, 0.17198383, 0.13491433]])In [250]: arr[:,arr[0].argsort()] Out[250]: array([[ 0. , 1. , 2. , 3. , 5. ],[ 0.25591603, 0.28292862, -2.22019292, -0.02259515, -0.62471185],[ 0.61927654, 0.66283367, 0.13491433, 0.17198383, -1.29263396]]) #lexsorth和argsort差不多,只不過它可以一次性對多個鍵數組執行間接排序(字典序) In [251]: first_name=np.array(['Bob','Jane','Steve','Bill','Barbara']) In [253]: last_name=np.array(['Jones','Arnold','Arnold','Jones','Walters'])In [255]: sorter=np.lexsort((first_name,last_name))In [257]: zip(last_name[sorter],first_name[sorter]) Out[257]: <zip at 0x7fabd526c9c8>In [258]: result=zip(last_name[sorter],first_name[sorter])In [259]: for i in result:...: print(i)...: ('Arnold', 'Jane') ('Arnold', 'Steve') ('Jones', 'Bill') ('Jones', 'Bob') ('Walters', 'Barbara') #因為鍵的應用化工順序是從最后一個傳入算起的,last_name是先于first_name被應用的

在有序數組中查找元素:searchsorted方法和digitize函數

searchsorted是一個在有序數組上執行二分查找的數組方法,只要將值插入到它返回的那個位置就能維持數組的有序性

In [260]: arr=np.array([0,1,3,4,6,8,9])In [261]: arr.searchsorted(7) Out[261]: 5 #傳入一組值就能得到一組索引 In [262]: arr.searchsorted([0,2,3,8]) Out[262]: array([0, 2, 2, 5]) #默認返回相等值組的左側索引,所以0返回的是0,可設置參數side='right'返回右側的索引 In [264]: arr.searchsorted([0,2,3,8],side='right') Out[264]: array([1, 2, 3, 6])

searchsorted的另一個用法

#假設我們有一個數據數組,還有一個表示'面元邊界'的數組 In [265]: data=np.floor(np.random.uniform(0,10000,size=50))In [266]: bins=np.array([0,100,1000,5000,10000])#面元邊界In [267]: data Out[267]: array([6618., 352., 9113., 548., 4637., 5329., 2652., 4140., 7872.,9155., 8363., 8999., 4795., 6819., 7908., 9426., 9311., 1404.,1714., 9879., 9805., 2066., 664., 4675., 517., 5033., 489.,7429., 8766., 3503., 8062., 8565., 8018., 1598., 949., 7391.,4964., 7647., 7935., 7558., 5278., 6102., 2964., 9117., 9239.,7934., 4382., 4984., 2188., 1298.]) #為了得到各數據點所屬區間的編號(其中1表示面元[0,100],以此類推) In [268]: labels=bins.searchsorted(data)In [269]: labels Out[269]: array([4, 2, 4, 2, 3, 4, 3, 3, 4, 4, 4, 4, 3, 4, 4, 4, 4, 3, 3, 4, 4, 3,2, 3, 2, 4, 2, 4, 4, 3, 4, 4, 4, 3, 2, 4, 3, 4, 4, 4, 4, 4, 3, 4,4, 4, 3, 3, 3, 3]) #通過pandas的groupby技術可以對源數據集進行拆分 In [271]: pd.Series(data).groupby(labels) Out[271]: <pandas.core.groupby.groupby.SeriesGroupBy object at 0x7fabd516d7b8>In [272]: pd.Series(data).groupby(labels).mean() Out[272]: 2 586.500000 3 3247.750000 4 7952.535714 dtype: float64 #Numpy的digitize函數也可用于計算面元編號, In [273]: np.digitize(data,bins) Out[273]: array([4, 2, 4, 2, 3, 4, 3, 3, 4, 4, 4, 4, 3, 4, 4, 4, 4, 3, 3, 4, 4, 3,2, 3, 2, 4, 2, 4, 4, 3, 4, 4, 4, 3, 2, 4, 3, 4, 4, 4, 4, 4, 3, 4,4, 4, 3, 3, 3, 3])

numpy的matrix類

從二維數組中選區一行[1,:]或一列[;,1]將會產生一個一維數組,這樣不利于矩陣運算,numpy提供了一個matrix類,其單行或列會以二維形式返回,且使用星號(*)的乘法直接就是矩陣乘法

不建議用numpy.matrix替代正規的ndarray,因為他們的應用面較窄,對于擁有大量線性代數運算的函數,可以考慮

In [274]: arr=np.arange(12).reshape((2,6)) #返回單行或單列返回一維數組 In [275]: arr Out[275]: array([[ 0, 1, 2, 3, 4, 5],[ 6, 7, 8, 9, 10, 11]])In [276]: arr[:,1] Out[276]: array([1, 7])In [278]: arr[1,:] Out[278]: array([ 6, 7, 8, 9, 10, 11]) #matrix類返回二維數組 In [279]: arr_m=np.matrix(arr)In [280]: arr_m[:,1] Out[280]: matrix([[1],[7]])In [281]: arr_m[1,:] Out[281]: matrix([[ 6, 7, 8, 9, 10, 11]])

matrix還有一個特殊屬性I,其功能是返回矩陣的逆

In [282]: arr=np.arange(12).reshape((2,6))In [283]: arr_m=np.matrix(arr)In [284]: arr_m.I Out[284]: matrix([[-0.23015873, 0.08730159],[-0.14920635, 0.06349206],[-0.06825397, 0.03968254],[ 0.01269841, 0.01587302],[ 0.09365079, -0.00793651],[ 0.17460317, -0.03174603]])

內存映像文件

內存映像,功能是能夠處理在內存中放不下的數據集

內存映像文件是一種將磁盤上的非常大的二進制數據文件當作內存中的數組進行處理的方式,numpy實現了一個類似于ndarray的memmap對象,它允許將大文件分成小段進行讀寫,而不是一次性將整個數組讀入內存。memmap也擁有和數組一樣的方法,基本上只要是能用于ndarray的算法,也能用于memmap

使用函數np.memmap并傳入文件路徑、數據類型、形狀以及文件模式,即可創建一個memmap

In [285]: mmap=np.memmap('mymmap',dtype='float64',mode='w+',shape=(10000,10000))...: In [286]: mmap Out[286]: memmap([[0., 0., 0., ..., 0., 0., 0.],[0., 0., 0., ..., 0., 0., 0.],[0., 0., 0., ..., 0., 0., 0.],...,[0., 0., 0., ..., 0., 0., 0.],[0., 0., 0., ..., 0., 0., 0.],[0., 0., 0., ..., 0., 0., 0.]]) #對memmap切片會返回磁盤上的數據的視圖,如果將數據賦值給這些視圖,數據會顯緩存在內存中(就向python的文件對象),調用flush即可將其寫入磁盤In [287]: mmap[:5] Out[287]: memmap([[0., 0., 0., ..., 0., 0., 0.],[0., 0., 0., ..., 0., 0., 0.],[0., 0., 0., ..., 0., 0., 0.],[0., 0., 0., ..., 0., 0., 0.],[0., 0., 0., ..., 0., 0., 0.]])In [288]: section=mmap[:5]In [289]: section[:]=np.random.randn(5,10000)In [290]: mmap.flush()In [291]: mmap Out[291]: memmap([[ 1.58111002, 1.90645244, -0.63471948, ..., -1.35606172,1.16922047, 0.3476418 ],[ 0.48324066, 0.63520092, -0.5317452 , ..., 0.69026956,0.35725548, -0.33512981],[ 0.43491278, -1.47961165, -0.17788593, ..., 2.36128756,0.93145793, -0.38050151],...,[ 0. , 0. , 0. , ..., 0. ,0. , 0. ],[ 0. , 0. , 0. , ..., 0. ,0. , 0. ],[ 0. , 0. , 0. , ..., 0. ,0. , 0. ]])In [292]: del mmap #刪除內存映像#只要某個內存映像超出了作用域,它就會被垃圾回收器回收,之前對其所作的任何修改都會被寫入磁盤,當打開一個已經存在的內存映像時,仍然需要指明數據類型和形狀,因為磁盤上的那個文件只是一塊二進制數據而已,沒有任何元數據 In [293]: mmap=np.memmap('mymmap',dtype='float64',shape=(10000,10000))In [294]: mmap Out[294]: memmap([[ 1.58111002, 1.90645244, -0.63471948, ..., -1.35606172,1.16922047, 0.3476418 ],[ 0.48324066, 0.63520092, -0.5317452 , ..., 0.69026956,0.35725548, -0.33512981],[ 0.43491278, -1.47961165, -0.17788593, ..., 2.36128756,0.93145793, -0.38050151],...,[ 0. , 0. , 0. , ..., 0. ,0. , 0. ],[ 0. , 0. , 0. , ..., 0. ,0. , 0. ],[ 0. , 0. , 0. , ..., 0. ,0. , 0. ]])

性能建議

使用numpy的數組運算一般都比純python循環快得多,大致注意以下事項:

將python循環和條件邏輯轉換為數組運算和布爾數組運算

盡量使用廣播

避免復制數據,盡量使用數組視圖(即切片)

利用ufunc及其各種方法

Cpython和numpy

可以將Cpython看作帶有靜態類型并能嵌入C函數的python,Cpython實現的代碼運行速度很快,下面是簡單的Cpython函數用于對一個和一維數組求和

from numpy cimport ndarray,float64_t def sum_element(ndarray[float64_t] arr):cdef py_ssize_t i,n=len(arr)cdef float64_t result=0for i in range(n):result+=arr[i]return result#Cpython處理這段代碼時,先將其翻譯為C代碼,然后編譯這些C代碼并創建一個python擴展,一般的工作流程是:得到能在python中運行的算法,然后再將其翻譯為Cpython(只需添加類型定義并完成一些其他必要的工作即可--只需你妹!!)

?

?

二 pandas模塊

1.pandas的數據結構:

Series

Series 是一維標簽數組(Data must be 1-dimension),能夠保存任何數據類型(整型,浮點型,字符串或其他Python對象類型)。軸標簽被稱為索引

>>> import numpy as np >>> import pandas as pd >>> pd.Series(np.random.randn(12))#Series函數用于創建Series 0 0.445457 1 1.410470 2 -0.669725 3 -0.907310 4 0.081393 5 0.034115 6 1.219609 7 0.135690 8 -0.353035 9 0.640904 10 0.218566 11 0.836471 dtype: float64 >>> pd.Series(np.random.randn(12).reshape(3,4))#只能傳如一維數組,否則會報錯 Traceback (most recent call last):File "<stdin>", line 1, in <module>File "/home/zelin/.local/lib/python3.6/site-packages/pandas/core/series.py", line 275, in __init__raise_cast_failure=True)File "/home/zelin/.local/lib/python3.6/site-packages/pandas/core/series.py", line 4165, in _sanitize_arrayraise Exception('Data must be 1-dimensional') Exception: Data must be 1-dimensional

Series的字符串表現形式為:索引在左邊,值在右邊,如果沒有為數據指定索引,Series會自動創建一個0到N-1(N為數據長度)的整數型索引

values、index和name

Series的values屬性和index屬性為數組類型,Series調用values或index后返回一個帶由值或索引的數組

Series對象本身和其索引都有一個name屬性,該功能和pandas的其他關鍵功能關系非常密切(需要設置,默認為空)

In [192]: obj=pd.Series([111,222,333,444,555])In [193]: obj Out[193]: 0 111 1 222 2 333 3 444 4 555 dtype: int64In [194]: obj.index Out[194]: RangeIndex(start=0, stop=5, step=1)In [195]: obj.values Out[195]: array([111, 222, 333, 444, 555])

創建Series索引

Series的索引/切片形式同python的數據類型列表字典類似,可以將Series看成是一個定長的有序字典,因為它是索引值到數據值的一個映射,同樣,Series也可以進行索引賦值就地修改

In [197]: ser=pd.Series([111,222,333],index=['a','b','c'])In [198]: ser Out[198]: a 111 b 222 c 333 dtype: int64

可以傳入字典來創建一個Series,如果只傳字典一個參數,則字典的鍵作為Series的索引,字典的值作為Series的值

如果傳入字典參數后,另外指定索引參數,則索引如果與字典的鍵不匹配,則以索引產生一個NaN值,如果索引與字典的鍵匹配,則產生的值等于字典的值,即字典的鍵不產生作用

In [199]: pd.Series({'a':111,'b':222}) Out[199]: a 111 b 222 dtype: int64In [200]: In [200]: pd.Series({'a':111,'b':222},index=['ccc','ddd']) Out[200]: ccc NaN ddd NaN dtype: float64

Series最重要的一個功能是,它在算術運算中會自動對其不同索引的數據,即兩個Series的相同索引進行運算,不同索引產生NaN值

In [201]: ser1=pd.Series({'a':1,'b':2,'c':3})In [202]: ser2=pd.Series({'c':3,'d':4,'e':5})In [203]: ser1+ser2 Out[203]: a NaN b NaN c 6.0 d NaN e NaN dtype: float64

isnull和notnull

判斷Series數據是否為NaN值

In [212]: ser=pd.Series({'a':1,'b':2,'c':3,'d':np.nan})In [213]: pd.isnull(ser) Out[213]: a False b False c False d True dtype: boolIn [214]: pd.notnull(ser) Out[214]: a True b True c True d False dtype: bool

?

?

DataFrame

DataFrame是一個2維標簽的數據結構,是一種表格型數據結構,它的列可以存在不同的類型,你可以把它簡單的想成Excel表格或SQL Table,或者是包含字典類型的Series。它是最常用的Pandas對象。和Series一樣,DataFrame接受許多不同的類型輸入:

??? 包含1維ndarray,列表對象,字典對象或者Series對象的字典對象
??? 2維的ndarray對象
??? 結構化或記錄型的ndarray
??? Series對象
??? 另一個DataFrame對象

#np.random.randn(12)產生一個服從正態分布的12個數字的一維數組,reshape(3,4)將數組重構為3行4列的二維數組 >>> pd.DataFrame(np.random.randn(12).reshape(3,4))#DataFrame函數用于創建DataFrame0 1 2 3 0 -0.862802 1.176531 -0.009699 -0.455003 1 1.051637 -0.199708 0.402293 0.014919 2 0.588871 0.059458 1.911373 2.224995

創建DataFrame

創建DataFrame的方法有很多很多,最常用的一種是直接傳入一個由長列表或數組組成的數組

data_dict={'states':['oooo','ssss','dddd'],'age':[11,12,12]} In [3]: df=pd.DataFrame(data_dict,index...: =['aaa','bbb','ccc'])In [4]: df Out[4]: states age aaa oooo 11 bbb ssss 12 ccc dddd 12 #如果制定類列的序列,則會根據序列排序 In [8]: df=pd.DataFrame(data_dict,index=['aaa','bbb','ccc'],columns=['age','stat...: es'])In [9]: df Out[9]: age states aaa 11 oooo bbb 12 ssss ccc 12 dddd#如果傳入的列序列在數據中找不到,則會產生NaN值 In [10]: df=pd.DataFrame(data_dict,index=['aaa','bbb','ccc'],columns=['age','sta...: tes','NAN']) In [11]: df Out[11]: age states NAN aaa 11 oooo NaN bbb 12 ssss NaN ccc 12 dddd NaN

索引切片

通過類似字典標記的方法,可以將DataFrame的列轉化為一個Series,返回的Series擁有原DataFrame相同的索引,且其name屬性也已經被相應地設置好了

In [10]: df=pd.DataFrame(data_dict,index=['aaa','bbb','ccc'],columns=['age','sta...: tes','NAN'])In [11]: df Out[11]: age states NAN aaa 11 oooo NaN bbb 12 ssss NaN ccc 12 dddd NaNIn [12]: df['age'] Out[12]: aaa 11 bbb 12 ccc 12 Name: age, dtype: int64

行也可以通過位置或者名稱的方式進行獲取,比如用索引字段ix

In [15]: df.ix['aaa'] Out[15]: age 11 states oooo NAN NaN Name: aaa, dtype: object

列可以通過賦值的方式進行修改(整列發生改變),若賦值的列名不存在,則會新增一列

In [16]: df['age']=100In [17]: df Out[17]: age states NAN aaa 100 oooo NaN bbb 100 ssss NaN ccc 100 dddd NaNIn [18]: df['num']=200In [19]: df Out[19]: age states NAN num aaa 100 oooo NaN 200 bbb 100 ssss NaN 200 ccc 100 dddd NaN 200

通過索引方式返回的列只是源數據的視圖,而不是副本,所以對返回的列進行修改,也會反映到源數據,修改列時可能會由警告,keying忽略不計

In [19]: df Out[19]: age states NAN num aaa 100 oooo NaN 200 bbb 100 ssss NaN 200 ccc 100 dddd NaN 200In [20]: sr=df['age']In [21]: sr['aaa']=3000 /home/zelin/anaconda3/bin/ipython:1: SettingWithCopyWarning: A value is trying to be set on a copy of a slice from a DataFrameSee the caveats in the documentation: http://pandas.pydata.org/pandas-docs/stable/indexing.html#indexing-view-versus-copy#!/home/zelin/anaconda3/bin/pythonIn [22]: sr Out[22]: aaa 3000 bbb 100 ccc 100 Name: age, dtype: int64In [23]: df Out[23]: age states NAN num aaa 3000 oooo NaN 200 bbb 100 ssss NaN 200 ccc 100 dddd NaN 200

如果給DataFrame傳入一個嵌套字典,即字典的值也是字典,它就會被解釋成:外層字典的鍵作為列,內層字典的鍵作為行

In [25]: df=pd.DataFrame({'ooo':{1:1,2:2,3:3},'ppp':{11:11,22:22,33:33,44:44}})In [27]: df Out[27]: ooo ppp 1 1.0 NaN 2 2.0 NaN 3 3.0 NaN 11 NaN 11.0 22 NaN 22.0 33 NaN 33.0 44 NaN 44.0

對DataFrame進行轉置,內層字典的鍵會被合并、排序以形成最終的索引,如果顯式指定列索引,則不會這樣

In [32]: df2=pd.DataFrame(df,index=(1,2,3,11,33))In [33]: df2 Out[33]: ooo ppp 1 1.0 NaN 2 2.0 NaN 3 3.0 NaN 11 NaN 11.0 33 NaN 33.0

可以輸入給DataFrame構造器的數據

類型說明
二維ndarray數據矩陣,還可以傳入行標和列標
由數組、列表、元組組成的字典每個序列會變成DataFrame的一列,所有序列的長度必須相同
由Series組成的字典每個Series會成一列。如果沒有顯式指定索引,則各Series的索引會被合并成結果的行索引
由字典組成的字典各內層字典會成為一列,鍵會被合并成結果的行索引,跟‘由Series組成的字典’的情況一樣
字典或Series的列表各項會成為DataFrame的一行,字典鍵或Series的索引的并集會成為DataFrame的列標
由列表或元組組成的列表類似二維ndarray
另一個DataFrame該DataFrame的索引將會被沿用,除非顯式指定了其他索引
numpy的maskedArray類似二維ndarray的情況,只是掩碼值在結果DataFrame會變成NA缺失值
??

如果設置了index和columns的name屬性,則這些信息會被顯式出來

In [34]: df=pd.DataFrame({'ooo':{1:1,2:2,3:3},'ppp':{11:11,22:22,33:33,44:44}})In [35]: df.index.name='year'In [36]: df.columns.name='state'In [37]: df Out[37]: state ooo ppp year 1 1.0 NaN 2 2.0 NaN 3 3.0 NaN 11 NaN 11.0 22 NaN 22.0 33 NaN 33.0 44 NaN 44.0

跟Series一樣,values屬性也會以二維ndarray的形式返回DataFrame中的數據

In [38]: df.values Out[38]: array([[ 1., nan],[ 2., nan],[ 3., nan],[nan, 11.],[nan, 22.],[nan, 33.],[nan, 44.]])

如果DataFrame各列的數據類型不同,則值數組的數據類型就會選用能兼容所有列的數據類型、

In [48]: df=pd.DataFrame({'a':1,'b':'b','c':3.44},index=['a','b','c'])In [49]: df.values Out[49]: array([[1, 'b', 3.44],[1, 'b', 3.44],[1, 'b', 3.44]], dtype=object)

如果字典的鍵的值只有一個,DateFrame的行數,會根據顯式指定的index的長度而變化,值重復

In [39]: df=pd.DataFrame({'a':1,'b':'b','c':3.44},index=['a'])In [40]: df Out[40]: a b c a 1 b 3.44In [41]: df=pd.DataFrame({'a':1,'b':'b','c':3.44},index=['a','b'])In [42]: df Out[42]: a b c a 1 b 3.44 b 1 b 3.44In [43]: df=pd.DataFrame({'a':1,'b':'b','c':3.44},index=['a','b','c'])In [44]: df Out[44]: a b c a 1 b 3.44 b 1 b 3.44 c 1 b 3.44

索引對象

pandas的索引對象負責管理軸標簽和其他元數據(比如軸名稱等),構建Series或DataFrame時,所用到的任何數組或者其他序列都會被轉化成一個index,Index對象是不可修改的(immutable),因此用戶不能對其進行修改(--否則會報錯)

In [50]: df=pd.DataFrame({'a':1,'b':'b','c':3.44},index=['a','b','c'])In [51]: df Out[51]: a b c a 1 b 3.44 b 1 b 3.44 c 1 b 3.44In [52]: index=df.indexIn [53]: index Out[53]: Index(['a', 'b', 'c'], dtype='object')In [54]: index[1] Out[54]: 'b'In [55]: index[1]='a' --------------------------------------------------------------------------- TypeError Traceback (most recent call last) <ipython-input-55-336c3a4c2807> in <module>() ----> 1 index[1]='a'~/anaconda3/lib/python3.7/site-packages/pandas/core/indexes/base.py in __setitem__(self, key, value)2063 2064 def __setitem__(self, key, value): -> 2065 raise TypeError("Index does not support mutable operations")2066 2067 def __getitem__(self, key):TypeError: Index does not support mutable operations

不可修改性非常重要,因為這樣才能使Index對象在多個數據結構之間安全共享,Index可以被集成從而實現特別的軸索引功能

In [57]: index=pd.Index(np.arange(3))In [58]: obj2=pd.Series([111,222,333],index=index)In [59]: obj2.index is index Out[59]: True

Index長的像數組,功能也類似一個固定大小的集合

In [58]: obj2=pd.Series([111,222,333],index=index)In [59]: obj2.index is index Out[59]: TrueIn [60]: 1 in obj2.index Out[60]: TrueIn [61]: 222 in obj2.index Out[61]: False

每個索引都有一些方法和屬性,他們可用于設置邏輯并回答有關該索引所包含的數據的常見問題

方法說明
append

鏈接另一個Index對象,產生一個新的Index對象

diff計算差集,并得到一個Index
intersection計算交集
union計算并集
isin計算一個指示各值是否都包含在參數集合種的布爾型數組
delete刪除索引i處的元素,并得到一個新的Index
drop刪除傳入的值,并得到新的Index
insert將元素插入索引i處,并得到一個新的Index
is_monotonic當各元素均大于等于前一個值時,返回True
is_unique當Index沒有重復值時,返回True
unique計算Index中唯一值的數組

Series和DataFrame的基本功能

重新索引reindex,其作用是創建一個適應新索引的新對象,調用Series的reindex將會根據新索引重排,如果某個索引值當前不存在,就引入缺失值,reindex的參數fill_value用以替換數據內的缺失值

In [62]: obj=pd.Series([1,2,3,4],index=['d','b','a','c'])In [64]: obj Out[64]: d 1 b 2 a 3 c 4 dtype: int64In [65]: obj.reindex(['a','b','c','d','e'])#重新排序,及某個索引值當前不存在,則引入缺失值 Out[65]: a 3.0 b 2.0 c 4.0 d 1.0 e NaN dtype: float64In [66]: obj.reindex(['a','b','c','d','e','f'],fill_value=1.1)#fill_value替換缺失值 Out[66]: a 3.0 b 2.0 c 4.0 d 1.0 e 1.1 f 1.1 dtype: float64

如果像時間序列這樣的有序數據,重新索引時可能需要做一些插值處理,method選項即可達到此目的,例如使用method=ffill可以實現向前填充(即復制排序前位的值),以及method=bfill向后填充(復制排序后位的值)

In [67]: obj=pd.Series(['blue','yellow','orange'],index=[0,2,4])In [68]: obj.reindex(np.arange(6)) Out[68]: 0 blue 1 NaN 2 yellow 3 NaN 4 orange 5 NaN dtype: objectIn [69]: obj.reindex(np.arange(6),method='ffill') Out[69]: 0 blue 1 blue 2 yellow 3 yellow 4 orange 5 orange dtype: objectIn [70]: obj=pd.Series(['blue','yellow','orange'],index=[0,2,4])In [71]: obj.reindex(np.arange(6),method='bfill')#后面沒有數據,則仍然為NaN值 Out[71]: 0 blue 1 yellow 2 yellow 3 orange 4 orange 5 NaN dtype: object

重新索引行和列或者都修改,傳入單個序列默認修改行索引,修改列標需要傳參給columns參數,但插值只能按行應用

In [73]: df=pd.DataFrame(np.arange(9).reshape(3,3),index=['a','b','c'],columns=[...: 'va','vb','vc'])In [74]: df Out[74]: va vb vc a 0 1 2 b 3 4 5 c 6 7 8In [75]: df.reindex(['a','b','c','d']) Out[75]: va vb vc a 0.0 1.0 2.0 b 3.0 4.0 5.0 c 6.0 7.0 8.0 d NaN NaN NaNIn [76]: df.reindex(columns=['vvva','vvvb','vvvc']) Out[76]: vvva vvvb vvvc a NaN NaN NaN b NaN NaN NaN c NaN NaN NaN

利用ix的標簽索引功能,重新索引更簡潔

In [77]: df=pd.DataFrame(np.arange(9).reshape(3,3),index=['a','b','c'],columns=[...: 'va','vb','vc'])In [78]: df Out[78]: va vb vc a 0 1 2 b 3 4 5 c 6 7 8In [79]: df.ix[['a','b','c','d'],['vva','vvb','vc']]Out[79]: vva vvb vc a NaN NaN 2.0 b NaN NaN 5.0 c NaN NaN 8.0 d NaN NaN NaN

reindex函數的參數

參數說明
index用作索引的新序列,既可以是Index實例,也可以是其他序列型的python數據結構,Index會被完全使用,就像沒有任何復制一樣
method插值(填充)方式
fill_value在重新索引過程種,需要引入缺失值使用的替代值
limit前向或后向填充時的最大填充量
level在Multilndex在指定級別上匹配簡單索引,否則選取其子集
copy默認為True,無論如何都復制,如果為False,則新舊相等就不復制

?

刪除指定軸上的項

drop方法

丟棄某條軸上的一個或多個項,只要有一個索引數組 或者列表即可,由于需要執行一些數據整理和集合邏輯,所以drop方法返回的是一個在指定軸上刪除了指定值的新對象

In [3]: ser=pd.Series(np.arange(5.),index=['a','b','c','d','e'])In [4]: ser Out[4]: a 0.0 b 1.0 c 2.0 d 3.0 e 4.0 dtype: float64In [5]: ser.drop('c')#獲取到的是新對象,而不是刪除源數據 Out[5]: a 0.0 b 1.0 d 3.0 e 4.0 dtype: float64In [6]: ser Out[6]: a 0.0 b 1.0 c 2.0 d 3.0 e 4.0 dtype: float64

索引、選取和過濾

Series的索引的工作方式類似numpy數組的索引,只不過Series的索引不只是整數,而且與普通python的切片不同,其末端是包含的(即封閉區間),索引就是一個數據,切片就是切一片數據

In [12]: obj=pd.Series(np.arange(4.),index=('a','b','c','d'))In [13]: obj Out[13]: a 0.0 b 1.0 c 2.0 d 3.0 dtype: float64In [14]: obj['a':'c'] Out[14]: a 0.0 b 1.0 c 2.0 dtype: float64

索引方式幾種特殊的情況,通過切片或布爾型數組選取行

In [15]: obj=pd.Series(np.arange(4.),index=('a','b','c','d'))In [16]: obj>2 Out[16]: a False b False c False d True dtype: boolIn [18]: obj[obj>2] Out[18]: d 3.0 dtype: float64

索引字段ix

可以通過Numpy式的標記法以及軸標簽從DataFrame中選取行和列的子集

In [31]: df=pd.DataFrame(np.arange(16).reshape(4,4),index=['o','p','q','r'],colu...: mns=['one','two','three','four'])In [37]: df Out[37]: one two three four o 0 1 2 3 p 4 5 6 7 q 8 9 10 11 r 12 13 14 15In [32]: df.ix['o',['one','two']]#[行索引,列標] Out[32]: one 0 two 1 Name: o, dtype: int64In [34]: df.ix[['o','p'],['one','two']]#位置參數,無需指定Out[34]: one two o 0 1 p 4 5In [36]: df.ix[df.one>3,:3]#one列大于3的所有數據Out[36]: one two three p 4 5 6 q 8 9 10 r 12 13 14

DataFrame的索引選項

obj[val]選取DataFrame的單個列或一組列,在一些特殊情況下會比較便利::布爾型數組(過濾行),切片(行切片),布爾型DataFrame(根據條件設置值)
obj.ix[val]選取DataFrame的單個行或一組行
obj.ix[:,val]選取單個列或列子集
obj.ix[[vla1,val2]]同時選取行和列(參數1為行,參數2為列)
reindex方法將一個或多個軸匹配到新索引
xs方法根據標簽選取單行或單列,并返回一個Series

icol、irow方法

根據整數位置選取單列或單行

get_value、set_value

根據行標簽和列標簽選取單個值

算術運算和數據對齊

pandas最重要的一個功能,它可以對不同索引的對象進行算術運算,在將對象相加時,如果存在不同的索引對,則該結果的索引對的并集(相同索引相加,不同索引并集,取空值NaN),自動的數據對齊操作在不重疊的索引處引入列NA值,缺失值會在算術運算種傳播

In [39]: s1=pd.Series([1,2,3,4],index=['a','c','d','e'])In [42]: s2=pd.Series([3,3,3,3,3],index=['a','c','e','f','g'])In [43]: s1+s2 Out[43]: a 4.0 c 5.0 d NaN e 7.0 f NaN g NaN dtype: float64

DataFrame的對齊操作

對于DataFrame,對齊操作會同時發生在行和列上,把他們相加后會返回一個新的DataFrame,其索引和列標為原來兩個DataFrame的并集(索引和列標不全相同,則為NaN,全相等則相加)

In [45]: df1=pd.DataFrame(np.arange(9).reshape(3,3),columns=list('bcd'),index=li...: st('xyz'))In [48]: df2=pd.DataFrame(np.arange(12.).reshape(4,3),columns=list('dbe'),index=...: list('xymn'))In [49]: df1+df2 Out[49]: b c d e m NaN NaN NaN NaN n NaN NaN NaN NaN x 1.0 NaN 2.0 NaN y 7.0 NaN 8.0 NaN z NaN NaN NaN NaN

在算術方法中的填充值

兩個DataFrame相加,不重疊部分會產生空值NaN,使用add方法將兩個DataFrame相加可以,以及一個fill_value參數,可以實現將不重疊部分填充值,然后再相加

In [11]: import numpy as npIn [12]: import pandas as pdIn [13]: df1=pd.DataFrame(np.arange(12).reshape((3,4)),columns=list('abcd'))In [14]: df2=pd.DataFrame(np.arange(20).reshape((4,5)),columns=list('abcde'))In [15]: df1+df2 Out[15]: a b c d e 0 0.0 2.0 4.0 6.0 NaN 1 9.0 11.0 13.0 15.0 NaN 2 18.0 20.0 22.0 24.0 NaN 3 NaN NaN NaN NaN NaNIn [16]: df1.add(df2) Out[16]: a b c d e 0 0.0 2.0 4.0 6.0 NaN 1 9.0 11.0 13.0 15.0 NaN 2 18.0 20.0 22.0 24.0 NaN 3 NaN NaN NaN NaN NaNIn [17]: df1.add(df2,fill_value=0)#并非在結果中填充,而是將不重疊部分填充為0值 Out[17]: a b c d e 0 0.0 2.0 4.0 6.0 4.0 1 9.0 11.0 13.0 15.0 9.0 2 18.0 20.0 22.0 24.0 14.0 3 15.0 16.0 17.0 18.0 19.0

與此類似,在對Series和DataFrame重新索引時,也可以指定一個填充值(reindex重新索引產生的是新數據,不會影響源數據,所以df1可以用兩次)

In [20]: df1.reindex(list('abcde'),fill_value=0) Out[20]: a b c d a 0 0 0 0 b 0 0 0 0 c 0 0 0 0 d 0 0 0 0 e 0 0 0 0In [21]: df1.reindex(columns=list('abcde'),fill_value=0)#重新索引產生的是新數據,不會影響源數據 Out[21]: a b c d e 0 0 1 2 3 0 1 4 5 6 7 0 2 8 9 10 11 0

算術方法:加減乘除

df1.add(df2)
df1.sub(df2)
df1.mul(df2)
df1.div(df2)


?

?

?

?

DataFrame和Series之間的運算

跟numpy一樣,DataFrame和Series之間的算術運算也是有明確規定的

廣播:即DataFrame和Series算術運算,會沒廣播到全DataFrame都和Series都進行運算,而不僅僅是單列/行

DataFrame和Series之間的算術運算會將Series的索引匹配到DataFrame的列,然后沿著行一直向下廣播,如果某個索引值在DataFrame的列或Series的索引種找不到,則參與運算的兩個對象就會被重新索引引以形成并集

默認匹配列,沿著行傳波

In [25]: df=pd.DataFrame(np.arange(12).reshape((4,3)),index=list('abcd'),columns...: =list('opq'))In [26]: df Out[26]: o p q a 0 1 2 b 3 4 5 c 6 7 8 d 9 10 11In [27]: ser=df.ix['a']#只能以行索引為參數,不然會報錯In [28]: ser Out[28]: o 0 p 1 q 2 Name: a, dtype: int64In [30]: df.add(ser) Out[30]: o p q a 0 2 4 b 3 5 7 c 6 8 10 d 9 11 13In [31]: df+ser Out[31]: o p q a 0 2 4 b 3 5 7 c 6 8 10 d 9 11 13

如果你希望匹配到行且在列上廣播,則必須使用算術運算方法

In [33]: df.add(ser,axis=0)#匹配行,即將Series的列標成為索引與DataFrame 并集 Out[33]: o p q a NaN NaN NaN b NaN NaN NaN c NaN NaN NaN d NaN NaN NaN o NaN NaN NaN p NaN NaN NaN q NaN NaN NaN

函數的應用和映射

Numpy的ufuncs(元素級數組方法)也可以用于操作pandas對象

另一個常見的操作是,將函數應用到由各列或行所形成的一維數組上,DataFrame的apply方法可實現此功能

apply,應用作為參數傳入的函數/方法功能

In [10]: df=pd.DataFrame(np.arange(12).reshape((4,3)),columns=list('xyz'),index=...: list('adcd'))In [11]: f=lambda x: x.max()-x.min()In [12]: df.apply(f)#使用作為參數傳入的函數功能 Out[12]: x 9 y 9 z 9 dtype: int64In [13]: df.apply(f,axis=1) Out[13]: a 2 d 2 c 2 d 2 dtype: int64

applymap 函數應用

元素級的python函數也是可以用的,使用applymap即可

In [15]: df=pd.DataFrame(np.random.randn(4,3),columns=list('xyz'),index=list('ab...: cd'))In [16]: f=lambda x:'%.2f'%xIn [17]: df.applymap(f) Out[17]: x y z a 0.33 1.56 -1.21 b 1.18 2.26 -2.17 c 0.59 -0.59 -0.26 d -0.43 -0.41 -1.09

map,Series的應用函數

之所以用applymap,因為Series也有一個應用函數map方法

In [19]: df['x'].map(f) Out[19]: a 0.33 b 1.18 c 0.59 d -0.43 Name: x, dtype: object

排序和排名

sort_index,根據索引排序,值也會跟著索引移動,數據默認是按行升序排列,參數axis設置軸向,ascending設置升/降序

In [20]: df=pd.DataFrame(np.random.randn(4,3),columns=list('xyz'),index=list('cd...: ab'))In [21]: df Out[21]: x y z c 0.574269 1.004828 -1.653797 d -1.153132 -2.733118 0.119374 a -1.616412 -1.232352 -0.053378 b 0.882328 -0.613165 2.238244In [22]: df.sort_index() Out[22]: x y z a -1.616412 -1.232352 -0.053378 b 0.882328 -0.613165 2.238244 c 0.574269 1.004828 -1.653797 d -1.153132 -2.733118 0.119374

sort_index如果需要根據某一列的值進行排序,將列名傳參給by參數即可,數據結構單個列字符串,多個列是列表

In [28]: df Out[28]: x y z c 0.574269 1.004828 -1.653797 d -1.153132 -2.733118 0.119374 a -1.616412 -1.232352 -0.053378 b 0.882328 -0.613165 2.238244In [29]: df.sort_index(by='x') /home/zelin/anaconda3/bin/ipython:1: FutureWarning: by argument to sort_index is deprecated, please use .sort_values(by=...)#!/home/zelin/anaconda3/bin/python Out[29]: x y z a -1.616412 -1.232352 -0.053378 d -1.153132 -2.733118 0.119374 c 0.574269 1.004828 -1.653797 b 0.882328 -0.613165 2.238244In [30]: df.sort_index(by=['x','z']) /home/zelin/anaconda3/bin/ipython:1: FutureWarning: by argument to sort_index is deprecated, please use .sort_values(by=...)#!/home/zelin/anaconda3/bin/python Out[30]: x y z a -1.616412 -1.232352 -0.053378 d -1.153132 -2.733118 0.119374 c 0.574269 1.004828 -1.653797 b 0.882328 -0.613165 2.238244

?

排名

排名和排序關系密切,且它會增設一個排名值(從1開始,一直到數組中有效數據的數量),它和numpy.argsort產生的間接排序索引差不多,只不過它可以破壞平級關系

rank

pandas對象的rank方法,為各組分配一個平均排名的方式破壞平級關系

In [32]: ser=pd.Series([7,-5,7,4,2,0,4])In [33]: ser Out[33]: 0 7 1 -5 2 7 3 4 4 2 5 0 6 4 dtype: int64In [34]: ser.rank() Out[34]: 0 6.5 1 1.0 2 6.5 3 4.5 4 3.0 5 2.0 6 4.5 dtype: float64

DataFrame可以在行或列上進行排名

In [37]: df.rank() Out[37]: a b 0 3.0 1.0 1 2.0 3.0 2 1.0 2.0 3 4.0 4.0In [38]: df.rank(axis=1) Out[38]: a b 0 1.0 2.0 1 1.0 2.0 2 1.0 2.0 3 1.0 2.0

rank的破壞平級method選項

method說明
average默認:在相等分組中,為各個值分配平均排名
min使用整個分組的最小排名
max使用整個分組的最大排名
first按值在原始數據種的出現順序分配排名

?

帶由重復值的軸索引

某個索引值對應多個值,則返回一個Series,而對應單個值的,則返回一個標量值

In [39]: ser=pd.Series([7,-5,7,4,2,0,4],index=['a','b','a','b','c','a','d'])In [40]: ser['a'] Out[40]: a 7 a 7 a 0 dtype: int64In [42]: ser['d'] Out[42]: 4

?

匯總和計算描述統計

pandas對象擁有一組常用的數學和統計方法,大部分屬于約簡和匯總統計

用于從Series中提取單個值(sum/mean等)或從DataFrame的行或列取一個Series,跟對應的Numpy數組方法相比,他們都是基于沒有缺失數據的假設而構建的

In [44]: df=pd.DataFrame([[1.4,np.nan],[7.1,-4.5],[np.nan,np.nan],[0.75,-1.3]],i...: ndex=list('abcd'),columns=['one','two'])In [45]: df Out[45]: one two a 1.40 NaN b 7.10 -4.5 c NaN NaN d 0.75 -1.3In [46]: df.sum() Out[46]: one 9.25 two -5.80 dtype: float64In [47]: df.sum(axis=1)#默認等于0列相加,axis=1行相加 Out[47]: a 1.40 b 2.60 c 0.00 d -0.55 dtype: float64In [48]: df.sum(axis=1,skipna=False)#默認排除NaN值,所以全NaN值則為0 Out[48]: a NaN b 2.60 c NaN d -0.55 dtype: float64

約簡方法的選項和方法

axisDataFrame的行用0,列用1
skipna排除缺失值,默認值為True
level如果軸是層次化索引的(即MultilIndex),則根據level分組約簡

?

?

?

?

idxmin、idxmax達到最小值和最大值的索引,間接統計

In [51]: df.idxmax() Out[51]: one b two d dtype: object

?

另一些方法是累計型的:cumsum

In [53]: df Out[53]: one two a 1.40 NaN b 7.10 -4.5 c NaN NaN d 0.75 -1.3In [52]: df.cumsum() Out[52]: one two a 1.40 NaN b 8.50 -4.5 c NaN NaN d 9.25 -5.8

一次性匯總多個統計信息:describe(),數值型和非數值型產生不同匯總信息

In [53]: df1#數值型 Out[53]: one two a 1.40 NaN b 7.10 -4.5 c NaN NaN d 0.75 -1.3In [54]: df.describe() Out[54]: one two count 3.000000 2.000000 mean 3.083333 -2.900000 std 3.493685 2.262742 min 0.750000 -4.500000 25% 1.075000 -3.700000 50% 1.400000 -2.900000 75% 4.250000 -2.100000 max 7.100000 -1.300000In [56]: df2#非數值型 Out[56]: a b 1 aa aa 2 bb bbb 3 cc ddd 4 dd cccIn [57]: df.describe() Out[57]: a b count 4 4 unique 4 4 top bb ccc freq 1 1

描述和匯總統計

count非NA值的數量
describe針對Series或各DataFrame列計算匯總統計
min、max計算最小值和最大值
argmin、argmax計算能夠獲取到最小值和最大值的索引位置(整數)
idxmin、inxmax計算能夠獲取到最小值和最大值的索引值
quantile計算樣本的分位數(0到1)
sum值的總和
mean值的平均數
median值的中位數
mad根據平均值計算平均絕對離差
var樣本值的方差
std樣本值的標準差
skew樣本值的偏度(三階矩)
kurt樣本值的峰度(四階矩)
cumsum樣本值的累計和
cummin、cummax樣本值的leis最小值和累計最大值
cumprod樣本值的累計積
diff計算一階差分(多用于時間序列)
pct_change計算百分數變化
??

?

?

?

?

?

?

?

?

?

?

?

?

?

?

?

?

?

?

?

?

?

?

?

?

?

?

?

?

?

?

?

?

?

分組運算:GroupBy技術

拆分--應用--合并

In [1]: import pandas as pdIn [2]: import numpy as np #構建DataFrame In [3]: df=pd.DataFrame({'key1':['a','a','b','b','a'],'key2':['one','two','one',...: 'two','one'],'data1':np.random.randn(5),'data2':np.random.randn(5)})In [4]: df Out[4]: key1 key2 data1 data2 0 a one -0.769863 0.321557 1 a two 0.163815 -0.635989 2 b one -1.048893 1.988060 3 b two -0.427548 0.322831 4 a one -1.115058 0.663252 #以鍵key1分組,獲取data1的GroupBy對象 In [5]: grouped=df['data1'].groupby(df['key1'])In [6]: grouped Out[6]: <pandas.core.groupby.groupby.SeriesGroupBy object at 0x7fd8664248d0> #GroupBy對象可以調用mean,sum等方法求平均值,和等值 In [7]: grouped.mean()#返回一個Series Out[7]: key1 a -0.573702 b -0.738221 Name: data1, dtype: float64

時間序列time series

時間序列是一種結構化數據形式,在多個時間點觀測或測量到的任何事物都可以形成一段時間序列,時間序列數據的意義取決于具體的應用場景,主要有以下幾種:

時間戳timestamp,特定的時刻 固定時期period,如2018全年 時間間隔interval,有起始和結束時間戳表示,時期period可以被看作間隔interval的特例 實驗/過程時間,每個時間點都是相對于特定起始時間的一個度量,例如,從放入冰箱時起,每分鐘橙子的溫度

python標準庫包含用于日期date,時間time,日歷calendar的datetime,time,calendar模塊,datetime.datetime是用得最多的數據類型

詳情見python之時間格式(datetime,time,calendar),此處只舉例

In [47]: from datetime import datetime#datetime模塊的datetime類用的最多In [48]: import timeIn [49]: import calendarIn [50]: datetime.now()#返回一個時間元組 Out[50]: datetime.datetime(2018, 10, 19, 15, 47, 17, 175724)In [51]: time.time()#返回一個時間戳 Out[51]: 1539935328.026199In [52]: calendar.calendar(2013)#傳入年份,返回一個日歷表 Out[52]: ' 2013\n\n January February March\nMo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su\n 1 2 3 4 5 6 1 2 3 1 2 3\n 7 8 9 10 11 12 13 4 5 6 7 8 9 10 4 5 6 7 8 9 10\n14 15 16 17 18 19 20 11 12 13 14 15 16 17 11 12 13 14 15 16 17\n21 22 23 24 25 26 27 18 19 20 21 22 23 24 18 19 20 21 22 23 24\n28 29 30 31 25 26 27 28 25 26 27 28 29 30 31\n\n April May June\nMo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su\n 1 2 3 4 5 6 7 1 2 3 4 5 1 2\n 8 9 10 11 12 13 14 6 7 8 9 10 11 12 3 4 5 6 7 8 9\n15 16 17 18 19 20 21 13 14 15 16 17 18 19 10 11 12 13 14 15 16\n22 23 24 25 26 27 28 20 21 22 23 24 25 26 17 18 19 20 21 22 23\n29 30 27 28 29 30 31 24 25 26 27 28 29 30\n\n July August September\nMo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su\n 1 2 3 4 5 6 7 1 2 3 4 1\n 8 9 10 11 12 13 14 5 6 7 8 9 10 11 2 3 4 5 6 7 8\n15 16 17 18 19 20 21 12 13 14 15 16 17 18 9 10 11 12 13 14 15\n22 23 24 25 26 27 28 19 20 21 22 23 24 25 16 17 18 19 20 21 22\n29 30 31 26 27 28 29 30 31 23 24 25 26 27 28 29\n 30\n\n October November December\nMo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su\n 1 2 3 4 5 6 1 2 3 1\n 7 8 9 10 11 12 13 4 5 6 7 8 9 10 2 3 4 5 6 7 8\n14 15 16 17 18 19 20 11 12 13 14 15 16 17 9 10 11 12 13 14 15\n21 22 23 24 25 26 27 18 19 20 21 22 23 24 16 17 18 19 20 21 22\n28 29 30 31 25 26 27 28 29 30 23 24 25 26 27 28 29\n 30 31\n'

時間序列基礎

以時間為索引構建Series序列

In [57]: from datetime import datetime #datetime傳入數字參數,表示年,月,日,時,分,秒,年月日為必傳參數,時分秒可選 In [62]: dates=[datetime(2018,10,19,10,0,0),datetime(2018,10,19,10,1,1),datetime...: (2018,10,19,10,2,2)]In [63]: s=pd.Series(np.random.randn(3),index=dates)In [64]: s Out[64]: 2018-10-19 10:00:00 2.450767 2018-10-19 10:01:01 -0.941043 2018-10-19 10:02:02 0.216157 dtype: float64 #這些datetime對象實際上是被放在列一個DatetimeIndex中,DatetimeIndex中的各個標量值是pandas的Timestamp對象 In [68]: type(s) Out[68]: pandas.core.series.Series#--利用python進行數據分析書中顯示為pandas.core.series.TimeSeries,與實際符,預計是新版本改變In [69]: s.index Out[69]: DatetimeIndex(['2018-10-19 10:00:00', '2018-10-19 10:01:01','2018-10-19 10:02:02'],dtype='datetime64[ns]', freq=None)

索引,選取,子集構造

In [82]: dates=[datetime(2018,10,19,10,0,0),datetime(2018,10,19,10,1,1),datetime...: (2018,10,19,10,2,2),datetime(2018,10,19,10,3,3),datetime(2018,10,19,10,...: 4,4)]In [83]: s=pd.Series(np.random.randn(5),index=dates)In [84]: s Out[84]: 2018-10-19 10:00:00 0.879305 2018-10-19 10:01:01 1.218865 2018-10-19 10:02:02 -0.859521 2018-10-19 10:03:03 -1.272252 2018-10-19 10:04:04 0.200955 dtype: float64In [85]: stamp=s.index[2]In [86]: s[stamp] Out[86]: -0.8595210222802377#獲取到第三行的值#索引也可傳入一個可被解釋為日期的字符串 In [90]: s['20181019100202'] Out[90]: -0.8595210222802377In [92]: s['19/10/2018 10:02:02'] Out[92]: -0.8595210222802377 #當傳入索引前相同部分的字符串,也可用作切片 In [93]: s['19/10/2018']時間字符串格式之一 Out[93]: 2018-10-19 10:00:00 0.879305 2018-10-19 10:01:01 1.218865 2018-10-19 10:02:02 -0.859521 2018-10-19 10:03:03 -1.272252 2018-10-19 10:04:04 0.200955 dtype: float64In [94]: s['20181019']#時間字符串格式之一 Out[94]: 2018-10-19 10:00:00 0.879305 2018-10-19 10:01:01 1.218865 2018-10-19 10:02:02 -0.859521 2018-10-19 10:03:03 -1.272252 2018-10-19 10:04:04 0.200955 dtype: float64#由于大部分時間序列數據都是按照時間先后排序的,因此也可以用不存在于該時間序類中的時間戳對其進行切片(即范圍查詢) In [98]: s['19/10/2018 10:0:0':'19/10/2018 10:01:02'] Out[98]: 2018-10-19 10:00:00 0.879305 2018-10-19 10:01:01 1.218865 dtype: float64#實例方法truncate也能實現截取兩個日期時間的Series,所選范圍為閉端,即包含所穿參數 In [105]: s.truncate(after='20181019100303',before='20181019100000') Out[105]: 2018-10-19 10:00:00 0.879305 2018-10-19 10:01:01 1.218865 2018-10-19 10:02:02 -0.859521 2018-10-19 10:03:03 -1.272252 dtype: float64

帶有重復索引的時間序列

#當索引為不重復項時,返回標量值,當索引為重復項時,返回Series序列 In [109]: s['20181001'] Out[109]: 2018-10-01 -1.217149 2018-10-01 -1.714301 dtype: float64In [113]: s['20181003'] Out[113]: 0.14757289913298496

注意:datetime不能傳入01,02等0開頭的參數,會報錯

In [122]: dates=[datetime(2011,01,02),datetime(2011,01,05),datetime(2011,01,07),...: datetime(2011,01,08),datetime(2011,01,10),datetime(2011,01,12)]File "<ipython-input-122-98aa28d7950b>", line 1dates=[datetime(2011,01,02),datetime(2011,01,05),datetime(2011,01,07),datetime(2011,01,08),datetime(2011,01,10),datetime(2011,01,12)]^ SyntaxError: invalid tokenIn [123]: dates=[datetime(2011,1,2),datetime(2011,1,5),datetime(2011,1,7),dateti...: me(2011,1,8),datetime(2011,1,10),datetime(2011,1,12)]

生成日期范圍

#pandas.date_range可用于指定長度的DatetimeIndex,默認情況下,產生按天計算的時間點,date_range默認保留起始和結束日期,即閉端 In [139]: index=pd.date_range('4/1/2018','4/10/2018')#月日年In [140]: s=pd.Series(np.random.randn(10),index=index)In [141]: s Out[141]: 2018-04-01 -0.667058 2018-04-02 1.781576 2018-04-03 -0.845532 2018-04-04 -1.121527 2018-04-05 0.572054 2018-04-06 -0.120728 2018-04-07 1.396313 2018-04-08 1.559138 2018-04-09 0.737590 2018-04-10 1.905737 Freq: D, dtype: float64 #如果給參數period傳入一個表示索引個數的數字,可以設定索引間隔時間,即時間差/periods In [149]: index=pd.date_range(start='4/1/2018',end='4/10/2018',periods=5)#表示間隔兩天,產生5個索引,即5等分時間差In [150]: s=pd.Series(np.random.randn(5),index=index)In [151]: s Out[151]: 2018-04-01 00:00:00 -1.440547 2018-04-03 06:00:00 0.295920 2018-04-05 12:00:00 0.297291 2018-04-07 18:00:00 -0.753377 2018-04-10 00:00:00 1.643616 dtype: float64 #如果希望產生一組被規范化到午夜的時間戳,normalize參數可實現該功能,即忽略時間,從開始日期的零點始,結束日期的零點終 In [155]: index=pd.date_range(start='4/1/2018 08:04:22',end='4/10/2018 12:12:21'...: ,periods=5)In [156]: index=pd.date_range(start='4/1/2018',end='4/10/2018',periods=5,normali...: ze=True)In [157]: s=pd.Series(np.random.randn(5),index=index)In [158]: s Out[158]: 2018-04-01 00:00:00 1.209585 2018-04-03 06:00:00 -1.129351 2018-04-05 12:00:00 -1.488379 2018-04-07 18:00:00 -0.882576 2018-04-10 00:00:00 -0.152073 dtype: float64

頻率和基礎偏移量

pandas中的頻率是由一個基礎頻率(hbase frequency)和一個乘數組成的,基礎頻率通常以一個字符串別名表示,比如'M'表示月,'H'表示小時,對于每個基礎頻率,都有一個被稱為日期偏移量(date offset)的對象與之對應

In [159]: from pandas.tseries.offsets import Hour,Minute In [160]: hour=Hour()#基礎頻率 In [161]: hour Out[161]: <Hour>In [162]: four_hours=Hour(4)#導入一個整數即可定義偏移量的倍數In [163]: four_hours Out[163]: <4 * Hours>#一般無需顯式創建這樣的對象,在date_range函數前傳入參數freq,參數值使用諸如'h','4h'這樣的字符串別名的整數倍 In [164]: dates=pd.date_range('20181211','20181220',freq='2d')#字符串別名不區分大小寫In [165]: s=pd.Series(np.random.randn(5),index=dates)In [166]: s Out[166]: 2018-12-11 -0.031886 2018-12-13 0.827174 2018-12-15 0.317349 2018-12-17 -1.938784 2018-12-19 -0.410817 Freq: 2D, dtype: float64#也可以傳入頻率字符串:如'4h30min',這種字符串可以被高效的解析為等效的表達式In [168]: dates=pd.date_range('20181211','20181220',freq='2d48h') In [170]: s=pd.Series(np.random.randn(3),index=dates)In [171]: s Out[171]: 2018-12-11 -1.380608 2018-12-15 -0.012547 2018-12-19 -0.858346 Freq: 4D, dtype: float64#大部分偏移量對象都可以用'+'加號連接 In [167]: Hour(2)+Minute(30) Out[167]: <150 * Minutes>

時間序列的常見基礎頻率表

注意:有些頻率描述的時間點不是均勻分隔的,如‘M’日里月末和’BM’每月最后一個工作日,對于前者,就取決于每月的天數,對于后者,還要考慮月末是不是周末,我們稱這些為錨點偏移量

別名偏移量類型說明
DDay每日歷日
BBussinessDay每工作日
HHour每小時
T/minMinute每分
SSecond每秒
L/msMilli每毫秒(即千分之一秒)
UMicro每微秒(即每百萬分之一秒)
MMonthEnd每月最后一個日歷日
BMBusinessMonthEnd每月最后一個工作日
MSMonthBegin每月第一個日歷日
BMSBusinessMonthBegin每月第一個工作日
W-MON,W-TUE....Week從指定的星期幾開始計算
WOM-1MON,WOM-2MON...?從指定的每月第一,第二...周的星期即,例如:WOM-3FRI表示每月的第三隔星期五
A-JAN,A-FEBYearEnd每年指定月份的最后一個日歷日
BA-JAN,BA-FEBBusinessYearEnd每年指定月份的最后一個工作日
AS-JAN,AS-FEBYearBegin每年指定月份的第一個日歷日
BAS-JAN,BAS-FEBBusinessYearBegin每年指定月份的第一個工作日

WOM日期

WOM(Week Of Month)是一種非常使用的頻率類,它以WOM開頭,它使你能獲得'每月第3隔星期五'之類的日期

In [172]: rng=pd.date_range('1/1/2018','9/1/2018',freq='WOM-3FRI')In [173]: list(rng) Out[173]: [Timestamp('2018-01-19 00:00:00', freq='WOM-3FRI'),Timestamp('2018-02-16 00:00:00', freq='WOM-3FRI'),Timestamp('2018-03-16 00:00:00', freq='WOM-3FRI'),Timestamp('2018-04-20 00:00:00', freq='WOM-3FRI'),Timestamp('2018-05-18 00:00:00', freq='WOM-3FRI'),Timestamp('2018-06-15 00:00:00', freq='WOM-3FRI'),Timestamp('2018-07-20 00:00:00', freq='WOM-3FRI'),Timestamp('2018-08-17 00:00:00', freq='WOM-3FRI')]

移動(超前或滯后)數據

移動(shifting)指的是沿著時間軸將數據前移或者后移,但保持索引不變

In [4]: ts=pd.Series(np.random.randn(4),index=pd.date_range('1/1/2018',periods=4...: ,freq='M')) #periods=4表示以1/1/2018為起始日期產生4個時間索引,間隔為月,即freq='M' In [5]: ts Out[5]: 2018-01-31 0.467078 2018-02-28 -0.664430 2018-03-31 -0.823731 2018-04-30 2.407555 Freq: M, dtype: float64In [14]: ts.shift(2)#正整數向下移 Out[14]: 2018-01-31 NaN 2018-02-28 NaN 2018-03-31 0.467078 2018-04-30 -0.664430 Freq: M, dtype: float64In [15]: ts.shift(-2)#負整數向上移動 Out[15]: 2018-01-31 -0.823731 2018-02-28 2.407555 2018-03-31 NaN 2018-04-30 NaN Freq: M, dtype: float64#shift通常用于計算一個時間序列或多個時間序列中的百分比變化,可以這樣表達: ts/ts.shift(1)-1 #由于單純的位移操作不會修改索引,所以部分數據會被丟棄,因此如果頻率已知,則可以將頻率freq傳給shift以便實現移動時間戳進行位移,而不是移動數據: In [17]: ts.shift(2,freq='M') Out[17]: 2018-03-31 0.467078 2018-04-30 -0.664430 2018-05-31 -0.823731 2018-06-30 2.407555 Freq: M, dtype: float64 #還可以使用其他頻率,于是就能非常靈活地對數據進行超前或滯后處理了 In [21]: ts.shift(1,'3d') Out[21]: 2018-02-03 0.467078 2018-03-03 -0.664430 2018-04-03 -0.823731 2018-05-03 2.407555 dtype: float64In [22]: ts.shift(3,'d') Out[22]: 2018-02-03 0.467078 2018-03-03 -0.664430 2018-04-03 -0.823731 2018-05-03 2.407555 dtype: float64

通過偏移量對日期進行位移

pandas的日期偏移量還可以用在datetime和Timestamp對象上

In [25]: from pandas.tseries.offsets import Day,MonthEnd In [26]: now=datetime(2011,11,7)In [27]: now+3*Day() Out[27]: Timestamp('2011-11-10 00:00:00') #如果加的是錨點偏移量,第一次增量會將原日期向前滾動到符合頻率規則的下一個日期,比如第一次位移的量可能沒有一個月那么長,就在當月 In [26]: now=datetime(2011,11,7)In [27]: now+3*Day() Out[27]: Timestamp('2011-11-10 00:00:00')In [28]: now+MonthEnd() Out[28]: Timestamp('2011-11-30 00:00:00')In [29]: now+2*MonthEnd() Out[29]: Timestamp('2011-12-31 00:00:00')In [30]: now+MonthEnd(2) Out[30]: Timestamp('2011-12-31 00:00:00') #通過錨點偏移量的rollforward和rollback方法,可以顯式的將日期前移或向后滾動 In [31]: offset=MonthEnd()In [32]: offset.rollforward(now)#向前翻滾就是本月 Out[32]: Timestamp('2011-11-30 00:00:00') In [33]: offset.rollback(now)#前后翻滾就是上一個月 Out[33]: Timestamp('2011-10-31 00:00:00') #結合groupby使用前后滾動 In [34]: ts=pd.Series(np.random.randn(20),index=pd.date_range('1/15/2018',period...: s=20,freq='4d'))In [35]: ts Out[35]: 2018-01-15 -1.123869 2018-01-19 0.691454 2018-01-23 -1.492071 2018-01-27 0.047393 2018-01-31 0.190645 2018-02-04 -1.427506 2018-02-08 0.318326 2018-02-12 -0.073011 2018-02-16 0.636296 2018-02-20 -0.570525 2018-02-24 -0.865244 2018-02-28 -0.356154 2018-03-04 -0.247588 2018-03-08 0.589253 2018-03-12 1.113633 2018-03-16 1.722783 2018-03-20 -2.332676 2018-03-24 -0.275168 2018-03-28 -0.171739 2018-04-01 -0.369748 Freq: 4D, dtype: float64In [36]: ts.groupby(offset.rollforward).mean()#全部轉換為幾類相同日期,然后分類 Out[36]: 2018-01-31 -0.337290 2018-02-28 -0.333974 2018-03-31 0.056928 2018-04-30 -0.369748 dtype: float64 #結合groupby函數使用滾動的封裝方法:resample In [38]: ts.resample('M',how='mean')#python2 /usr/bin/ipython3:1: FutureWarning: how in .resample() is deprecated the new syntax is .resample(...).mean()#! /bin/sh Out[38]: 2018-01-31 -0.337290 2018-02-28 -0.333974 2018-03-31 0.056928 2018-04-30 -0.369748 Freq: M, dtype: float64 #結合groupby函數使用滾動的封裝方法:resampleIn [39]: ts.resample('M').mean()#python3 Out[39]: 2018-01-31 -0.337290 2018-02-28 -0.333974 2018-03-31 0.056928 2018-04-30 -0.369748 Freq: M, dtype: float64

時區處理

時區信息來自python庫pytz,它使python可以使用Olso數據庫(匯編了世界時區信息),由于pandas包裝了pytz的功能,因此可以不用記其API,只要記住時區名即可,時區名可以在文檔中找到,也可以通過交互查看

In [42]: import pytz#時區信息庫 In [43]: pytz.timezone('US/Eastern')#獲取時區信息, Out[43]: <DstTzInfo 'US/Eastern' LMT-1 day, 19:04:00 STD> In [48]: pytz.common_timezones[1]#時區名稱列表 Out[48]: 'Africa/Accra'

本地化和轉換

默認情況下,pandas中的時間序列是單純的(naive)時區,其索引的tz字段為None,在生成日期范圍的時候還可以加上一個時區集,從單純到本地化的轉換是通過tz_locallize方法處理的:

In [56]: rng=pd.date_range('3/9/2018 9:30',periods=6,freq='D')In [57]: ts=pd.Series(np.random.randn(len(rng)),index=rng)In [58]: ts Out[58]: 2018-03-09 09:30:00 -1.470021 2018-03-10 09:30:00 -1.171575 2018-03-11 09:30:00 0.739337 2018-03-12 09:30:00 -0.990569 2018-03-13 09:30:00 0.007370 2018-03-14 09:30:00 0.389544 Freq: D, dtype: float64In [62]: rng.tzIn [63]: #返回值為空In [52]: ts1=pd.date_range('3/9/2018 9:30',periods=10,freq='D',tz='UTC') Out[52]: DatetimeIndex(['2018-03-09 09:30:00+00:00', '2018-03-10 09:30:00+00:00','2018-03-11 09:30:00+00:00', '2018-03-12 09:30:00+00:00','2018-03-13 09:30:00+00:00', '2018-03-14 09:30:00+00:00','2018-03-15 09:30:00+00:00', '2018-03-16 09:30:00+00:00','2018-03-17 09:30:00+00:00', '2018-03-18 09:30:00+00:00'],dtype='datetime64[ns, UTC]', freq='D') In [55]: ts1.tz#默認tz屬性為None Out[55]: <UTC> In [65]: ts_utc=ts.tz_localize('UTC') #使用tz_localize轉換為UTC本地時區 In [66]: ts_utc Out[66]: 2018-03-09 09:30:00+00:00 -1.470021 2018-03-10 09:30:00+00:00 -1.171575 2018-03-11 09:30:00+00:00 0.739337 2018-03-12 09:30:00+00:00 -0.990569 2018-03-13 09:30:00+00:00 0.007370 2018-03-14 09:30:00+00:00 0.389544 Freq: D, dtype: float64#當時間序列被本地化到某個特定時區,就可以用tz_convert將其轉換為別的時區了In [67]: ts_utc.tz_convert('US/Eastern') Out[67]: 2018-03-09 04:30:00-05:00 -1.470021 2018-03-10 04:30:00-05:00 -1.171575 2018-03-11 05:30:00-04:00 0.739337 2018-03-12 05:30:00-04:00 -0.990569 2018-03-13 05:30:00-04:00 0.007370 2018-03-14 05:30:00-04:00 0.389544 Freq: D, dtype: float64 #tz_localize和tz_convert是DatetimeIndex的實例方法,對于單純時間戳的本地化操作還會檢查夏令時轉變期附近容易混淆或不存在的時間

操作時區意識型Timestamp對象

跟時間序列和日期范圍差不多,Timestamp對象也能被從單純型(naive)本地化為時區意識型(time zone-aware),并從一個時區轉換為另一個時區

#單純時區和本地時區之間可以靈活轉換 In [70]: stamp=pd.Timestamp('2011-03-12 04:00')#創建TimestampIn [71]: stamp Out[71]: Timestamp('2011-03-12 04:00:00')In [72]: stamp_utc=stamp.tz_localize('utc')In [73]: stamp_utc Out[73]: Timestamp('2011-03-12 04:00:00+0000', tz='UTC')In [75]: stamp_utc.tz_convert('US/Eastern') Out[75]: Timestamp('2011-03-11 23:00:00-0500', tz='US/Eastern') #創建Timestamp時,還可以傳入一個時區信息 In [76]: stamp_moscow=pd.Timestamp('2011-01-12 04:00',tz='Europe/Moscow')In [77]: stamp_moscow Out[77]: Timestamp('2011-01-12 04:00:00+0300', tz='Europe/Moscow')

時區意識型Timestamp對象在內部保存了一個UTC時間戳(自UNIX紀元(1970年1月1日0時)算起的納秒數)。這個UTC值在時區轉換過程中是不會發生變化的

In [76]: stamp_moscow=pd.Timestamp('2011-01-12 04:00',tz='Europe/Moscow')In [77]: stamp_moscow Out[77]: Timestamp('2011-01-12 04:00:00+0300', tz='Europe/Moscow')In [78]: stamp_utc.value Out[78]: 1299902400000000000In [79]: stamp_utc.tz_convert('US/Eastern').value Out[79]: 1299902400000000000

當使用pandas的DateOffset對象執行時間算術運算時,運算過程會自動關注是否存在夏令時轉變期

#夏令時轉變前30分鐘--沒有區別 In [80]: from pandas.tseries.offsets import HourIn [81]: stamp=pd.Timestamp('2012-03-12 01:30',tz='US/Eastern')In [82]: stamp+Hour() Out[82]: Timestamp('2012-03-12 02:30:00-0400', tz='US/Eastern')In [83]: stamp Out[83]: Timestamp('2012-03-12 01:30:00-0400', tz='US/Eastern') #夏令時轉變前90分鐘--少了一個小時,why? In [84]: stamp=pd.Timestamp('2012-11-04 00:30',tz='US/Eastern')In [85]: stamp Out[85]: Timestamp('2012-11-04 00:30:00-0400', tz='US/Eastern')In [86]: stamp+2*Hour() Out[86]: Timestamp('2012-11-04 01:30:00-0500', tz='US/Eastern')

不同時區之間的運算

如果兩個時間序列的時區不同,在將他們合并到一起時,最終結果就會是UTC,由于時間戳其實是以UTC存儲的,所以并不需要發生任何轉換

In [87]: rng=pd.date_range('3/7/2012 9:30',periods=10,freq='B')In [88]: ts=pd.Series(np.random.randn(10),index=rng)In [89]: ts Out[89]: 2012-03-07 09:30:00 1.946924 2012-03-08 09:30:00 0.305003 2012-03-09 09:30:00 0.529779 2012-03-12 09:30:00 -1.501415 2012-03-13 09:30:00 -0.837557 2012-03-14 09:30:00 0.529487 2012-03-15 09:30:00 0.055145 2012-03-16 09:30:00 -0.746819 2012-03-19 09:30:00 -0.824349 2012-03-20 09:30:00 0.627202 Freq: B, dtype: float64In [90]: ts1=ts[:7].tz_localize('Europe/London')In [91]: ts2=ts[2:].tz_localize('Europe/Moscow')In [92]: ts1 Out[92]: 2012-03-07 09:30:00+00:00 1.946924 2012-03-08 09:30:00+00:00 0.305003 2012-03-09 09:30:00+00:00 0.529779 2012-03-12 09:30:00+00:00 -1.501415 2012-03-13 09:30:00+00:00 -0.837557 2012-03-14 09:30:00+00:00 0.529487 2012-03-15 09:30:00+00:00 0.055145 Freq: B, dtype: float64In [93]: ts2 Out[93]: 2012-03-09 09:30:00+04:00 0.529779 2012-03-12 09:30:00+04:00 -1.501415 2012-03-13 09:30:00+04:00 -0.837557 2012-03-14 09:30:00+04:00 0.529487 2012-03-15 09:30:00+04:00 0.055145 2012-03-16 09:30:00+04:00 -0.746819 2012-03-19 09:30:00+04:00 -0.824349 2012-03-20 09:30:00+04:00 0.627202 Freq: B, dtype: float64In [94]: ts1+ts2#為什么是NaN值????????? Out[94]: 2012-03-07 09:30:00+00:00 NaN 2012-03-08 09:30:00+00:00 NaN 2012-03-09 05:30:00+00:00 NaN 2012-03-09 09:30:00+00:00 NaN 2012-03-12 05:30:00+00:00 NaN 2012-03-12 09:30:00+00:00 NaN 2012-03-13 05:30:00+00:00 NaN 2012-03-13 09:30:00+00:00 NaN 2012-03-14 05:30:00+00:00 NaN 2012-03-14 09:30:00+00:00 NaN 2012-03-15 05:30:00+00:00 NaN 2012-03-15 09:30:00+00:00 NaN 2012-03-16 05:30:00+00:00 NaN 2012-03-19 05:30:00+00:00 NaN 2012-03-20 05:30:00+00:00 NaN dtype: float64

?

?

?

?

?

?

?

三 matplotlib模塊

matplotlib是一個用于創建出版質量圖表的桌面繪圖包(主要是2D方面),其目的是為python構建一個MATLAB式的繪圖接口,它不僅支持各種操作系統上許多不同的GUI后端,而且還能將圖片導出為各種常見的矢量(vector)和光柵(raster)圖

標PDF JPG什么的

先來看一個使用制圖小例子

>>> import matplotlib.pyplot as plt >>> x=np.linspace(0,10,1000) >>> y=np.sin(x) >>> y=np.sin(x)+1 >>> z=np.cos(x**2)+1 >>> plt.plot(x,y,label='$\sin x+1$',color='red',linewidth=2) [<matplotlib.lines.Line2D object at 0x08CEB350>] >>> plt.figure(figsize=(8,4)) <Figure size 800x400 with 0 Axes> >>> plt.plot(x,z,'b--',label='$\cos x^2+1$') [<matplotlib.lines.Line2D object at 0x0A78FBF0>] >>> plt.xlabel('time(s)') Text(0.5, 0, 'time(s)') >>> plt.ylabel('volt') Text(0, 0.5, 'volt') >>> plt.title('example') Text(0.5, 1.0, 'example') >>> plt.ylim(0,2.2) (0, 2.2) >>> plt.legend() <matplotlib.legend.Legend object at 0x0A786610> >>> plt.show() ''' 安裝matplotlib,需要使用apt-get安裝依賴包(不是用pip3安裝) sudo apt-get install python3-tk pip3 install matplotlib '''>>> import matplotlib >>> import matplotlib.pyplot as plt >>> fg=plt.figure() >>> ax1=fg.add_subplot(2,2,1) >>> ax2=fg.add_subplot(2,2,2) >>> ax3=fg.add_subplot(2,2,3 ... ) >>> plt.gcf() <Figure size 640x480 with 3 Axes> >>> plt.show()

四? ? scipy模塊

Numpy提供了多維數組功能,但它只是一般的數組,并不是矩陣,例如,當兩個數組相乘時,只是對應元素相乘,而不是矩陣乘法,scipy提供了真正的矩陣,以及大量基于矩陣預算的對象和函數,但是scipy是依賴于numpy庫的,numpy還是基礎庫

Scipy包含的功能有最優化、線性代數、積分、插值、擬合、特殊函數、快速傅里葉變換、信號處理和圖像處理、常微分方程求解和其他科學與工程中常用的計算

#-*- coding:utf-8 -*- #求解非線性方程組2x1-x2^2=1,x1^2-x2=2 from scipy.optimize import fsolve #導入求解方程組的函數 def f(x): #定義需要求解的方程組x1=x[0]x2=x[1]return [2*x1-x2**2-1,x1**2-x2-2] result=fsolve(f,[1,1]) #輸入初值[1,1]并求解 print(result)#數值積分 from scipy import integrate #導入積分函數 def g(x): #定義被積函數return (1-x**2)**0.5 pi_2,err=integrate.quad(g,-1,1) #積分結果和誤差 print(pi_2*2) #由微積分知識知道積分結果為圓周率pi的一半

?

?

?

?

?

?

?

?

?

?

?

?

?

總結

以上是生活随笔為你收集整理的利用python进行数据分析_从删库到跑路的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。