DataFrame中的字符串,但dtype是object


96

为什么Pandas告诉我我有对象,尽管所选列中的每个项目都是一个字符串-即使经过显式转换也是如此。

这是我的DataFrame:

<class 'pandas.core.frame.DataFrame'>
Int64Index: 56992 entries, 0 to 56991
Data columns (total 7 columns):
id            56992  non-null values
attr1         56992  non-null values
attr2         56992  non-null values
attr3         56992  non-null values
attr4         56992  non-null values
attr5         56992  non-null values
attr6         56992  non-null values
dtypes: int64(2), object(5)

他们五个dtype object。我将这些对象明确转换为字符串:

for c in df.columns:
    if df[c].dtype == object:
        print "convert ", df[c].name, " to string"
        df[c] = df[c].astype(str)

然后,尽管显示,df["attr2"]仍然是正确的。dtype objecttype(df["attr2"].ix[0]str

熊猫区分int64float64object。没有时背后的逻辑是什么dtype str?为什么被str覆盖object


来到这里是因为即使每个“是”字符串,连接也会由于“对象类型”而失败
Monica Heddneck

Answers:


145

dtype对象来自NumPy,它描述ndarray中元素的类型。ndarray中的每个元素都必须具有相同的字节大小。对于int64和float64,它们是8个字节。但是对于字符串,字符串的长度不是固定的。因此,熊猫没有直接将字符串的字节保存在ndarray中,而是使用对象ndarray来保存指向对象的指针,因此,这种ndarray的dtype是object。

这是一个例子:

  • int64数组包含4个int64值。
  • 对象数组包含4个指向3个字符串对象的指针。

在此处输入图片说明


3
但是请注意,具有“对象”类型的列对DataFrame读/写操作的性能具有重大影响
erwanp '18

我能以某种方式将数据类型返回为字符串吗?我知道我总是可以使用type(df [“ column”]。iloc [0]),但它可能是nan
user1953366 '19

7

接受的答案是好的。只是想提供一个参考文档的答案。该文档说:

熊猫使用对象dtype来存储字符串。

正如主要评论所说:“不用担心;它应该像这样。” (尽管可接受的答案在解释“为什么”方面做得很好,字符串是可变长度的)

但是对于字符串,字符串的长度不是固定的。


为什么我需要将传递的每个列都转换为scipy或sklearn astype(str)才能接受?似乎我应该能够一开始将其应用于所有列。
Tinkinc

我不明白 @Tinkinc如果将列转换为字符串会怎样?这个答案似乎是将所有列都astype(str)转换为的一种优雅方法,尽管我仍然想知道字符串转换是否必要
Red Pea

我无法填充(0)我数据框中的所有对象都停留在(1,nan)而不是(1,0)
Tinkinc

抱歉@Tinkinc我还是不明白。我想提供帮助,但是您的问题听起来比“堆栈溢出”评论要复杂得多。考虑问一个问题,或加入我的聊天室。(刚刚邀请您)
红豌豆

5

@HYRY的答案很好。我只想提供更多背景信息。

阵列存储的数据作为连续的固定大小的存储器块。这些属性的结合使阵列可以快速进行数据访问。例如,考虑您的计算机可能如何存储32位整数数组[3,0,1]

在此处输入图片说明

如果您要求计算机获取数组中的第3个元素,它将从头开始,然后跨64位跳转到第3个元素。确切知道要跳过多少位才可以使数组快速运行

现在考虑字符串的顺序['hello', 'i', 'am', 'a', 'banana']。字符串是大小不同的对象,因此,如果您尝试将它们存储在连续的内存块中,它将最终看起来像这样。

在此处输入图片说明

现在,您的计算机没有快速的方法来访问随机请求的元素。克服这个问题的关键是使用指针。基本上,将每个字符串存储在某个随机的内存位置,然后用每个字符串的内存地址填充数组。(内存地址只是整数。)所以现在,事情看起来像这样

在此处输入图片说明

现在,如果您像以前一样要求计算机获取第三个元素,它可以跨64位跳转(假设内存地址是32位整数),然后再执行一个步骤来获取字符串。

NumPy面临的挑战是不能保证指针实际上指向字符串。这就是为什么它将dtype报告为“对象”的原因。

无耻地插入我自己的博客文章,最初是在此进行讨论的。


奈斯利written..Thanks
tedd

1

从1.0.0版开始(2020年1月),pandas作为实验功能被引入,它通过提供对字符串类型的一流支持pandas.StringDtype

虽然您仍然会object默认看到,但是可以通过指定dtypeof pd.StringDtype或简单地使用新类型'string'

>>> pd.Series(['abc', None, 'def'])
0     abc
1    None
2     def
dtype: object
>>> pd.Series(['abc', None, 'def'], dtype=pd.StringDtype())
0     abc
1    <NA>
2     def
dtype: string
>>> pd.Series(['abc', None, 'def']).astype('string')
0     abc
1    <NA>
2     def
dtype: string

2
不要使用这个。正如他们所说,The implementation may change without warning.这意味着新的更新将破坏您的旧程序。
NoName

1
好吧,这一切都取决于您要使用它的目的。如果要在需要连续升级软件包且API损坏导致不可接受的维护负担的生产系统中使用它,那么可以肯定,请密切注意“实验性”一词,但如果您使用熊猫来进行探索性的如果脚本的生命周期没有增加一天的工作量,那么这些担忧对您几乎没有什么意义。
fuglede

从Pandas 1.1开始,API似乎已稳定下来现在可以将所有dtypes转换为StringDtype
D3f0
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.