現象:
Numpy區分了str和object類型,其中dtype(‘S’)和dtype(‘O’)分別對應於str和object.
然而,pandas缺乏這種區別 str和object類型都對應dtype(‘O’)類型,即使強制類型為dtype(‘S’)也無濟於事
>>> import pandas as pd >>> import numpy as np >>> >>> >>> np.dtype(str) dtype('S') >>> np.dtype(object) >>> >>> dtype('O') >>> df = pd.DataFrame({'a': np.arange(5)}) >>> df a 0 0 1 1 2 2 3 3 4 4 >>> df.a.dtype dtype('int64') >>> df.a.astype(str).dtype dtype('O') >>> df.a.astype(object).dtype dtype('O') >>> df.a.astype(str).dtype dtype('O')
原理:
先說結論:
Numpy的字符串dtypes不是python字符串.pandas使用python字符串,.
numpy與pandas的字符串不同的含義:
>>> x = np.array(['Testing', 'a', 'string'], dtype='|S7') >>> x array([b'Testing', b'a', b'string'], dtype='|S7') >>> >>> >>> y = np.array(['Testing', 'a', 'string'], dtype=object) >>> y array(['Testing', 'a', 'string'], dtype=object)
現在,一個是numpy字符串dtype(固定寬度,類似c的字符串),另一個原生python字符串數組.
如果我們試圖超過7個字符,我們會看到立即的差異.numpy字符串dtype版本將被截斷,而numpy對象dtype版本可以是任意長度
>>> x[1] = 'a really really really long' >>> x array([b'Testing', b'a reall', b'string'], dtype='|S7') >>> >>> y[1] = 'a really really really long' >>> y array(['Testing', 'a really really really long', 'string'], dtype=object)
盡管存在unicode固定長度字符串dtype,但| s dtype字符串不能正確地保持unicode
最后,numpy的字符串實際上是可變的,而Python字符串則不是.
>>> z = x.view(np.uint8) >>> z array([ 84, 101, 115, 116, 105, 110, 103, 97, 32, 114, 101, 97, 108, 108, 115, 116, 114, 105, 110, 103, 0], dtype=uint8) >>> z+=1 >>> x array([b'Uftujoh', b'b!sfbmm', b'tusjoh\x01'], dtype='|S7')
由於所有這些原因,pandas選擇不允許類似C的固定長度字符串作為數據類型.
正如所注意到的那樣,嘗試將python字符串強制轉換為固定的numpy字符串將無法在pandas中使用.相反,它總是使用本機python字符串,對大多數用戶來說,它的行為更直觀.
那為什么np.view可以驗證
NumPy文檔里對ndarray.view方法的說明:
-
ndarray.view(dtype=None, type=None)
-
New view of array with the same data。
-
返回數據的新視圖。
除了view()方法,還有我們熟悉的reshape()方法也可以返回一個視圖,至於其他方法也可以返回視圖
import numpy as np a = np.arange(10) b = a.reshape(5,2) c = a.view() c.shape = (2,5) a_base = a.base b_base = b.base c_base = c.base a_base, b_base, c_base (None, array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]), array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]))
對程序的說明,
-
首先創建一個具有10個數據的1維數組a,shape為(10, )。
-
b是reshape方法返回的a的一個視圖(view),此時b是一個2維數組,它的shape為(5,2)。
-
c是view方法返回的a的一個視圖,此時c的shape為(10, ),當執行c.shape = (2, 5)后c的shape變為(2, 5)。
-
b_base和c_base說明b和c只是a的一個視圖,共享a的數據,雖然它們的shape各不相同。
接着我們來看看各個數組的base,
>>>a.base is None True >>>b.base is a True >>>c.base is a True
如果一個數組的base是None,說明這個數組的數據是自己的,它是這個數據的所有者;如果不是None,則說明數據在不是自己的,他只能通過數據擁有者才能訪問。
如果兩個數組的base相同,說明它們指向同一個數據擁有者。
ndarray.base
-
NumPy文檔說明: Base object if memory is from some other object.
-
base對象說明數據是否來自別的對象。
-
上面這個例子,a.base是None,說明a自己擁有數據,不是來自別人的,而b和c的base都是a,說明它們都沒有自己的數據,都是a的。
下面代碼的運行結果表明,這三個數組中只有a是數據的所有者,而b和c都不是。
a.flags.owndata, b.flags.owndata, c.flags.owndata
結果:(True, False, False)
驗證:
b[1,1] = 88
把原來的3改成了88。結果我們看下圖,三個數組里的3同時被改成88。