Mei*_*ham 19 python numpy pandas
Numpy似乎区分str和object类型.比如我可以做::
>>> import pandas as pd
>>> import numpy as np
>>> np.dtype(str)
dtype('S')
>>> np.dtype(object)
dtype('O')
Run Code Online (Sandbox Code Playgroud)
其中D型("S")和D型("O")对应于str和object分别.
但是熊猫似乎就缺少了区分,并要挟str到object.::
>>> df = pd.DataFrame({'a': np.arange(5)})
>>> df.a.dtype
dtype('int64')
>>> df.a.astype(str).dtype
dtype('O')
>>> df.a.astype(object).dtype
dtype('O')
Run Code Online (Sandbox Code Playgroud)
强制类型dtype('S')也无济于事.::
>>> df.a.astype(np.dtype(str)).dtype
dtype('O')
>>> df.a.astype(np.dtype('S')).dtype
dtype('O')
Run Code Online (Sandbox Code Playgroud)
这种行为有什么解释吗?
Joe*_*ton 27
Numpy的字符串dtypes不是python字符串.
因此,pandas故意使用本机python字符串,这需要一个对象dtype.
首先,让我演示一下numpy的字符串不同的含义:
In [1]: import numpy as np
In [2]: x = np.array(['Testing', 'a', 'string'], dtype='|S7')
In [3]: y = np.array(['Testing', 'a', 'string'], dtype=object)
Run Code Online (Sandbox Code Playgroud)
现在,'x'是一个numpy字符串dtype(固定宽度,类似c的字符串),y是一个原生python字符串数组.
如果我们试图超过7个字符,我们会看到立即的差异.字符串dtype版本将被截断:
In [4]: x[1] = 'a really really really long'
In [5]: x
Out[5]:
array(['Testing', 'a reall', 'string'],
dtype='|S7')
Run Code Online (Sandbox Code Playgroud)
对象dtype版本可以是任意长度:
In [6]: y[1] = 'a really really really long'
In [7]: y
Out[7]: array(['Testing', 'a really really really long', 'string'], dtype=object)
Run Code Online (Sandbox Code Playgroud)
接下来,|Sdtype字符串不能正确保存unicode,尽管还有一个unicode固定长度字符串dtype.我暂时会跳过一个例子.
最后,numpy的字符串实际上是可变的,而Python字符串则不是.例如:
In [8]: z = x.view(np.uint8)
In [9]: z += 1
In [10]: x
Out[10]:
array(['Uftujoh', 'b!sfbmm', 'tusjoh\x01'],
dtype='|S7')
Run Code Online (Sandbox Code Playgroud)
出于所有这些原因,pandas选择不允许类似C的固定长度字符串作为数据类型.正如您所注意到的那样,尝试将python字符串强制转换为固定的numpy字符串将无法正常工作pandas.相反,它总是使用本机python字符串,它对大多数用户来说更直观.
如果您来到这里想了解pandas'string'和dtypes之间的差异,请阅读此处。object从 pandas 1.5.3 开始,这两种 dtypes 之间有两个主要区别。
objectdtype 不仅可以存储字符串,还可以存储混合数据类型,因此如果要将值转换为字符串,astype(str)就是规定的方法。然而,这会将所有值转换为字符串,甚至 NaN 也变成文字'nan'字符串。string是可以为 null 的数据类型,因此转换为'string'会将 NaN 保留为 null 值。
x = pd.Series(['a', float('nan'), 1], dtype=object)
x.astype(str).tolist() # ['a', 'nan', '1']
x.astype('string').tolist() # ['a', <NA>, '1']
Run Code Online (Sandbox Code Playgroud)
这样做的结果是,对objectdtype 列执行的字符串操作(例如计数字符、比较)会返回numpy.int等,而对dtypenumpy.bool执行的相同操作会返回 nullable或dtypes。特别是,对于对dtype执行的比较,NaN 比较返回 False(因为 NaN 不等于任何值) ,而对于对 dtype 执行的比较,则返回False。'string'pd.Int64pd.Booleanobjectpd.NApd.NA'string'
x = pd.Series(['a', float('nan'), 'b'], dtype=object)
x == 'a'
0 True
1 False
2 False
dtype: bool
y = pd.Series(['a', float('nan'), 'b'], dtype='string')
y == 'a'
0 True
1 <NA>
2 False
dtype: boolean
Run Code Online (Sandbox Code Playgroud)
因此,对于'string'dtype,null 处理更加灵活,因为您可以根据fillna()需要调用 etc. 来处理 null 值。1
stringdtype更清晰如果 pandas 列是objectdtype,则其中的值可以替换为任何值。例如,其中的字符串可以替换为整数,这样就可以了(例如x下面)。如果您希望其中的每个值都是字符串,那么之后可能会产生不良后果。stringdtype 不存在这个问题,因为一个字符串只能被另一个字符串替换(例如y下面)。
x = pd.Series(['a', 'b'], dtype=str)
y = pd.Series(['a', 'b'], dtype='string')
x[1] = 3 # OK
y[1] = 3 # ValueError
y[1] = '3' # OK
Run Code Online (Sandbox Code Playgroud)
这样做的优点是您可以select_dtypes()仅选择字符串列。换句话说,对于objectdtypes,无法识别字符串列,但对于'string'dtypes,可以。
df = pd.DataFrame({'A': ['a', 'b', 'c'], 'B': [[1], [2,3], [4,5]]}).astype({'A': 'string'})
df.select_dtypes('string') # only selects the string column
A
0 a
1 b
2 c
df = pd.DataFrame({'A': ['a', 'b', 'c'], 'B': [[1], [2,3], [4,5]]})
df.select_dtypes('object') # selects the mixed dtype column as well
A B
0 a [1]
1 b [2, 3]
2 c [4, 5]
Run Code Online (Sandbox Code Playgroud)
字符串 Dtype'string'有存储选项(python 和 pyarrow),如果字符串很短,pyarrow 非常高效。看下面的例子:
lst = np.random.default_rng().integers(1000000, size=1000).astype(str).tolist()
x = pd.Series(lst, dtype=object)
y = pd.Series(lst, dtype='string[pyarrow]')
x.memory_usage(deep=True) # 63041
y.memory_usage(deep=True) # 10041
Run Code Online (Sandbox Code Playgroud)
正如您所看到的,如果字符串很短(上例中最多 6 个字符),pyarrow 消耗的内存会减少 6 倍以上。但是,如以下示例所示,如果字符串很长,则几乎没有任何区别。
z = x * 1000
w = (y.astype(str) * 1000).astype('string[pyarrow]')
z.memory_usage(deep=True) # 5970128
w.memory_usage(deep=True) # 5917128
Run Code Online (Sandbox Code Playgroud)
1例如str.contains,类似的直觉已经存在于。str.match
x = pd.Series(['a', float('nan'), 'b'], dtype=object)
x.str.match('a', na=np.nan)
0 True
1 NaN
2 False
dtype: object
Run Code Online (Sandbox Code Playgroud)