NumPy 超詳細教程(2):資料型別

丹楓無跡發表於2019-03-18

系列文章地址


NumPy 資料型別

1、NumPy 中的資料型別

NumPy 支援比 Python 更多種類的數值型別,下表所列的資料型別都是 NumPy 內建的資料型別,為了區別於 Python 原生的資料型別,boolintfloatcomplexstr 等型別名稱末尾都加了 _

print(numpy.dtype) 所顯示的都是 NumPy 中的資料型別,而非 Python原生資料型別。

型別名稱 描述
bool_ 布林型別
unicode_ / unicode / str_ / str0(零非字母O) Unicode 字串
int8 / byte
int16 / short
int32 / intc / int_ / long
int64 / longlong / intp / int0(零非字母O)
uint8 / ubyte
uint16 / ushort
uint32 / uintc
uint64 / ulonglong / uintp / uint0(零非字母O)
float16 / half 半精度浮點數,包括:1 個符號位,5 個指數位,10 個尾數位
float32 / single 單精度浮點數,包括:1 個符號位,8 個指數位,23 個尾數位
float64 / float_ / double 雙精度浮點數,包括:1 個符號位,11 個指數位,52 個尾數位
complex64 / singlecomplex 複數,表示雙 32 位浮點數(實數部分和虛數部分)
complex128 / complex_ / cfloat / cdouble /
longcomplex / clongfloat / clongdouble
複數,表示雙 64 位浮點數(實數部分和虛數部分)
datetime64 NumPy 1.7 開始支援的日期時間型別
timedelta64 表示兩個時間之間的間隔

這裡有點不理解,我是 win7 64 位系統,上述的型別都是我實測得到的,但是,我檢視原始碼,裡面卻是如下定義的。總之,為了安全起見,還是建議用 int32、int64 等無歧義的型別。

int_ = long
intp = long
int64 = long
int0 = long

class long(signedinteger):
    """ 64-bit integer. Character code 'l'. Python int compatible. """
    pass
複製程式碼

補充:複數的概念

我們把形如 z=a+bi(a, b均為實數)的數稱為複數,其中 a 稱為實部,b 稱為虛部,i 稱為虛數單位。 當虛部 b=0 時,複數 z 是實數; 當虛部 b!=0 時,複數 z 是虛數; 當虛部 b!=0,且實部 a=0 時,複數 z 是純虛數。

2、datetime64 的使用

Ⅰ、簡單示例

例一:

import numpy as np

a = np.datetime64('2019-03-01')
print(a)
複製程式碼

輸出:

2019-03-01
複製程式碼

例二:

import numpy as np

a = np.datetime64('2019-03')
print(a)
複製程式碼

輸出:

2019-03
複製程式碼

看到沒有,可以僅顯示到“月”,是不是很贊?

Ⅱ、單位使用

datetime64 可以指定使用的單位,單位包括年('Y'),月('M'),周('W')和天('D'),而時間單位是小時('h'),分鐘('m') ),秒('s'),毫秒('ms'),微秒('us'),納秒('ns'),皮秒('ps'),飛秒('fs'),阿託秒('as')。

例三: 周('W')是一個比較奇怪的單位,如果是週四,則顯示當前,如果不是,則顯示上一個週四。後來我想,大概是因為 1970-01-01 是週四

import numpy as np

a = np.datetime64('2019-03-07', 'W')
b = np.datetime64('2019-03-08', 'W')
print(a, b)
複製程式碼

輸出:(2019-03-07 是週四)

2019-03-07 2019-03-07
複製程式碼

例四: 從字串建立 datetime64 型別時,預設情況下,NumPy 會根據字串自動選擇對應的單位。

import numpy as np

a = np.datetime64('2019-03-08 20:00')
print(a.dtype)
複製程式碼

輸出:

datetime64[m]
複製程式碼

例五: 也可以強制指定使用的單位。

import numpy as np

a = np.datetime64('2019-03', 'D')
print(a)
複製程式碼

輸出:

2019-03-01
複製程式碼

例六: 由上例可以看出,2019-032019-03-01 所表示的其實是同一個時間。 事實上,如果兩個 datetime64 物件具有不同的單位,它們可能仍然代表相同的時刻。並且從較大的單位(如月份)轉換為較小的單位(如天數)是安全的。

import numpy as np

print(np.datetime64('2019-03') == np.datetime64('2019-03-01'))
複製程式碼

輸出:

True
複製程式碼

例七: 從字串建立日期時間陣列時,如果單位不統一,則一律轉化成其中最小的單位。

import numpy as np

a = np.array(['2019-03', '2019-03-08', '2019-03-08 20:00'], dtype='datetime64')
print(a)
print(a.dtype)
複製程式碼

輸出:

['2019-03-01T00:00' '2019-03-08T00:00' '2019-03-08T20:00']
datetime64[m]
複製程式碼

Ⅲ、配合 arange 函式使用

**例八:**一個月的所有天數

import numpy as np

a = np.arange('2019-02', '2019-03', dtype='datetime64[D]')
print(a)
複製程式碼

輸出:

['2019-02-01' '2019-02-02' '2019-02-03' '2019-02-04' '2019-02-05'
 '2019-02-06' '2019-02-07' '2019-02-08' '2019-02-09' '2019-02-10'
 '2019-02-11' '2019-02-12' '2019-02-13' '2019-02-14' '2019-02-15'
 '2019-02-16' '2019-02-17' '2019-02-18' '2019-02-19' '2019-02-20'
 '2019-02-21' '2019-02-22' '2019-02-23' '2019-02-24' '2019-02-25'
 '2019-02-26' '2019-02-27' '2019-02-28']
複製程式碼

例九: 間隔也可以是 3 天('3D')這種形式哦。

import numpy as np

a = np.arange('2019-02', '2019-03', dtype='datetime64[3D]')
print(a)
複製程式碼

輸出:

['2019-02-01' '2019-02-04' '2019-02-07' '2019-02-10' '2019-02-13'
 '2019-02-16' '2019-02-19' '2019-02-22' '2019-02-25']
複製程式碼

發現沒有,這裡少了 2019-02-28。我認為是個 BUG,沒道理去掉的。

Ⅳ、Datetime64 和 Timedelta64 運算

例一: timedelta64 表示兩個 Datetime64 之間的差。timedelta64 也是帶單位的,並且和相減運算中的兩個 Datetime64 中的較小的單位保持一致。

import numpy as np

a = np.datetime64('2019-03-08') - np.datetime64('2019-03-07')
b = np.datetime64('2019-03-08') - np.datetime64('2019-03-07 08:00')
c = np.datetime64('2019-03-08') - np.datetime64('2019-03-07 23:00', 'D')

print(a, a.dtype)
print(b, b.dtype)
print(c, c.dtype)
複製程式碼

輸出:

1 days timedelta64[D]
960 minutes timedelta64[m]
1 days timedelta64[D]
複製程式碼

看 c 的表示式,因為強制限定了單位,所以 np.datetime64('2019-03-07 23:00', 'D') 所表示的時間其實是 2019-03-07,那麼結果是 1 也就好理解了。

例二:

import numpy as np

a = np.datetime64('2019-03') + np.timedelta64(20, 'D')
print(a)
複製程式碼

輸出:

2019-03-21
複製程式碼

Ⅴ、Timedelta64 單獨的運算

**例一:**生成 Timedelta64

import numpy as np

a = np.timedelta64(1, 'Y')    # 方式一
b = np.timedelta64(a, 'M')    # 方式二
print(a)
print(b)
複製程式碼

輸出:

1 years
12 months
複製程式碼

**例二:**加減乘除

import numpy as np

a = np.timedelta64(1, 'Y')
b = np.timedelta64(6, 'M')

print(a + b)
print(a - b)
print(2 * a)
print(a / b)
複製程式碼

輸出:

18 months
6 months
2 years
2.0
複製程式碼

例三: 但是,年('Y')和月('M')這兩個單位是經過特殊處理的,它們無法和其他單位進行運算,一年有幾天?一個月有幾個小時?這些都是不確定的。

import numpy as np

a = np.timedelta64(1, 'M')
b = np.timedelta64(a, 'D')
複製程式碼

輸出:

TypeError: Cannot cast NumPy timedelta64 scalar from metadata [M] to [D] according to the rule 'same_kind'
複製程式碼

Ⅵ、numpy.datetime64 與 datetime.datetime 相互轉換

import numpy as np
import datetime

dt = datetime.datetime(2018, 9, 1)
dt64 = np.datetime64(dt, 'D')
print(dt64, dt64.dtype)

dt2 = dt64.astype(datetime.datetime)
print(dt2)
複製程式碼

輸出:

2018-09-01 datetime64[D]
2018-09-01
複製程式碼

Ⅶ、工作日功能(busday)

busday 預設週一至週五是工作日。該實現基於一個 weekmask,包含 7 個布林標誌,用於工作日。

**例一:**busday_offset busday_offset 將指定的偏移量應用於工作日,單位天('D')。例如計算下一個工作日:

import numpy as np

a = np.busday_offset('2019-03-08', 1)
print(a)
複製程式碼

輸出:

2019-03-11
複製程式碼

例二: 如果當前日期為非工作日,則預設是報錯的。

import numpy as np

a = np.busday_offset('2019-03-09', 1)
print(a)
複製程式碼

輸出:

ValueError: Non-business day date in busday_offset
複製程式碼

例三: 可以指定 forwardbackward 規則來避免報錯。

import numpy as np

a = np.busday_offset('2019-03-09', 1, roll='forward')
b = np.busday_offset('2019-03-09', 1, roll='backward')
print(a)
print(b)

c = np.busday_offset('2019-03-09', 0, roll='forward')
d = np.busday_offset('2019-03-09', 0, roll='backward')
print(c)
print(d)
複製程式碼

輸出:

2019-03-12
2019-03-11
2019-03-11
2019-03-08
複製程式碼

可以指定偏移量為 0 來獲取當前日期向前或向後最近的工作日,當然,如果當前日期本身就是工作日,則直接返回當前日期。

例四:

import numpy as np

a = np.busday_offset('2019-05', 1, roll='forward', weekmask='Sun')
print(a)
複製程式碼

輸出:

2019-05-12
複製程式碼

母親節是 5 月的第二個星期日,本例就可以用於返回母親節具體的日期。來解釋一下:weekmask 引數在這裡可以傳星期的英文簡寫(注意是簡寫 Mon、Tue、Wed、Thu、Fri、Sat、Sun,全拼報錯的),指定向前或向後到星期幾。上面程式碼的含義就是:前進道 2019-05-01 後的第二個(不要忘了下標從 0 開始的)星期日。

這個功能對老美來說也許有用,但是在中國,誰來給我求個端午節是幾月幾號?

**例五:**is_busday 返回指定日期是否是工作日。

import numpy as np

a = np.is_busday(np.datetime64('2019-03-08'))
b = np.is_busday('2019-03-09')
print(a)
print(b)
複製程式碼

輸出:

True
False
複製程式碼

**例六:**busday_count 返回兩個日期之間的工作日數量。

import numpy as np

a = np.busday_count(np.datetime64('2019-03-01'), np.datetime64('2019-03-10'))
b = np.busday_count('2019-03-10', '2019-03-01')
print(a)
print(b)
複製程式碼

輸出:

6
-6
複製程式碼

**例七:**count_nonzero 統計一個 datetime64['D'] 陣列中的工作日天數。

import numpy as np

c = np.arange('2019-03-01', '2019-03-10', dtype='datetime64')
d = np.count_nonzero(np.is_busday(c))
print(d)
複製程式碼

輸出:

6
複製程式碼

例八: 自定義周掩碼值,即指定一週中哪些星期是工作日。

import numpy as np

a = np.is_busday('2019-03-08', weekmask=[1, 1, 1, 1, 0, 1, 0])
b = np.is_busday('2019-03-09', weekmask='1111010')
print(a)
print(b)
複製程式碼

輸出:

False
True
複製程式碼

周掩碼值還可以直接用星期單詞縮寫列出所有的工作日,下面所示的周掩碼錶示的工作日是:週一週二週三週四週六週日,週五為休息日。

weekmask='Mon Tue Wed Thu Sat Sun'
複製程式碼

3、資料型別物件:dtype

資料型別物件是用來描述與陣列對應的記憶體區域如何使用,這依賴如下幾個方面:

  • 資料的型別(整數,浮點數或者 Python 物件)
  • 資料的大小(例如, 整數使用多少個位元組儲存)
  • 資料的位元組順序(小端法"<"或大端法">",大端法高位元組在前低位元組在後,小端法低位元組在前高位元組在後)
  • 在結構化型別的情況下,欄位的名稱、每個欄位的資料型別和每個欄位所取的記憶體塊的部分(見例三)
  • 如果資料型別是子陣列,它的形狀和資料型別位元組順序是通過對資料型別預先設定"<"或">"來決定的。

Ⅰ、例項化 dtype 物件

dtype 物件構造語法:

numpy.dtype(obj, align=False, copy=False)
複製程式碼
引數 描述
object 要轉換為資料型別物件的物件
align 如果為 True,填充欄位使其類似 C 的結構體,只有當 object 是字典或逗號分隔的字串時才可以是 True
copy 複製 dtype 物件,如果為 False,則是對內建資料型別物件的引用

例一: int8, int16, int32, int64 四種資料型別可以使用字串 'i1', 'i2', 'i4', 'i8' 代替。(見字元程式碼)

import numpy as np

dt = np.dtype('i4')
print(dt)
複製程式碼

輸出:

int32
複製程式碼

例二:

import numpy as np

dt = np.dtype('<i4')
print(dt)
複製程式碼

輸出:

int32
複製程式碼

例三: 本例定義一個結構化資料型別 student,包含字串欄位 name,整數字段 age,並將這個 dtype 應用到 ndarray 物件。

import numpy as np
student = np.dtype([('name', 'S20'), ('age', 'i1')])
print(student)

a = np.array([('tom', 21), ('Jerry', 18)], dtype=student)
print(a)
複製程式碼

輸出:

[('name', 'S20'), ('age', 'i1')]
[(b'tom', 21) (b'Jerry', 18)]
複製程式碼

Ⅱ、字元程式碼

字元程式碼 對應型別
b 布林型
i 有符號整型,'i1', 'i2', 'i4', 'i8' 對應 int8, int16, int32, int64
u 無符號整型,'u1', 'u2', 'u4', 'u8' 對應 uint8, uint16, uint32, uint64
f 浮點型,'f2', 'f4', 'f8' 對應 float16, float32, float64
c 複數,'c8', 'c16' 對應 complex64, complex128
m timedelta64(時間間隔),本質上是個 int64
M(大寫) datetime64(日期時間)
O(大寫) Python 物件
S(大寫)/ a (byte-)字串,只能包含 ASCII 碼字元,S 或 a 後帶數字表示字串長度,超出部分將被截斷,例如 S20、a10
U(大寫) Unicode 字串,U 後帶數字表示字串長度,超出部分將被截斷,例如 U20
V(大寫) bytes 陣列,V 後帶數字表示陣列長度,超出部分將被截斷,不足則補零

這裡主要講下 M 和 V 的使用,其他都比較簡單好理解,可以看上面的例子。

字元程式碼 M 的使用示例:

import numpy as np

student = np.dtype([('name', 'S4'), ('age', 'M8[D]')])
print(student)

a = np.array([('tom', '2011-01-01'), ('Jerry', np.datetime64('2012-05-17'))], dtype=student)
print(a)
print(a['age'].dtype)
複製程式碼

輸出:

[('name', 'S4'), ('age', '<M8[D]')]
[(b'tom', '2011-01-01') (b'Jerr', '2012-05-17')]
datetime64[D]
複製程式碼

這裡必須寫成 M8[單位],不加單位報:Cannot cast NumPy timedelta64 scalar from metadata [D] to according to the rule 'same_kind'

字元程式碼 V 的使用示例:

import numpy as np

student = np.dtype([('name', 'V8'), ('age', 'i1')])
print(student)

a = np.array([(b'tom', 21), (b'Jerry', 18)], dtype=student)
print(a)
print(a['name'].dtype)
複製程式碼

輸出:

[('name', 'V8'), ('age', 'i1')]
[(b'\x74\x6F\x6D\x00\x00\x00\x00\x00', 21)
 (b'\x4A\x65\x72\x72\x79\x00\x00\x00', 18)]
|V8
複製程式碼

4、numpy.datetime_data

語法:

numpy.datetime_data(dtype, /)
複製程式碼

**引數:**只能是 datetime64timedelta64 型別 **返回值:**返回一個元組 ('單位', 步長)

例一:

import numpy as np

dt_25s = np.dtype('timedelta64[25s]')
print(np.datetime_data(dt_25s))
複製程式碼

輸出:

('s', 25)
複製程式碼

例二:

import numpy as np

dt_25s = np.dtype('timedelta64[25s]')
b = np.array([1, 2, 3, 4, 5], dt_25s).astype('timedelta64[s]')
print(b)
print(b.dtype)
複製程式碼

輸出:

[ 25  50  75 100 125]
timedelta64[s]
複製程式碼

本例中,b 是一個 narray,資料型別從 timedelta64[25s] 轉成了 timedelta64[s],所以陣列中每個數都要乘以 25。

5、numpy.datetime_as_string

將日期時間陣列轉換為字串陣列。

語法:

numpy.datetime_as_string(arr, unit=None, timezone='naive', casting='same_kind')
複製程式碼
引數 描述
arr datetimes64 陣列
unit 'auto' 或者 datetime64 單位。
timezone 時區
casting 在日期時間單位之間進行更改時允許進行轉換。有以下可選值:'no', 'equiv', 'safe', 'same_kind', 'unsafe'。

例一:

import numpy as np

dt_array = np.arange('2019-03-01', '2019-03-10', dtype='datetime64[D]')
str_array = np.datetime_as_string(dt_array)

print(str_array)
print(str_array.dtype)
複製程式碼

輸出:

['2019-03-01' '2019-03-02' '2019-03-03' '2019-03-04' '2019-03-05'
 '2019-03-06' '2019-03-07' '2019-03-08' '2019-03-09']
<U28
複製程式碼

**例二:**unit的使用示例 預設情況下,unit=None,如果陣列中的 datetime64 元素單位不一致,則會統一轉化為其中最小的單位形式輸出,如果 unit='auto' 則會保持原樣輸出。當然,如果指定了單位,則按指定的單位格式輸出。

import numpy as np

dt_array = np.array(['2019-03', '2019-03-08', '2019-03-08 20:00'], dtype='datetime64')

str_array1 = np.datetime_as_string(dt_array)
str_array2 = np.datetime_as_string(dt_array, unit='auto')
str_array3 = np.datetime_as_string(dt_array, unit='D')
print(str_array1)
print(str_array2)
print(str_array3)
複製程式碼

輸出:

['2019-03-01T00:00' '2019-03-08T00:00' '2019-03-08T20:00']
['2019-03-01' '2019-03-08' '2019-03-08T20:00']
['2019-03-01' '2019-03-08' '2019-03-08']
複製程式碼

歡迎關注我的公眾號

大齡碼農的Python之路

掃碼關注我的個人公眾號

相關文章