系列文章地址
NumPy 資料型別
1、NumPy 中的資料型別
NumPy 支援比 Python 更多種類的數值型別,下表所列的資料型別都是 NumPy 內建的資料型別,為了區別於 Python 原生的資料型別,bool
、int
、float
、complex
、str
等型別名稱末尾都加了 _
。
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-03
和 2019-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
複製程式碼
例三: 可以指定 forward 或 backward 規則來避免報錯。
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, /)
複製程式碼
**引數:**只能是 datetime64 或 timedelta64 型別 **返回值:**返回一個元組 ('單位', 步長)
例一:
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']
複製程式碼