DataFrame中的字符串,但dtype是对象

Xip*_*ias 86 python types numpy series pandas

为什么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)
Run Code Online (Sandbox Code Playgroud)

其中五个是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)
Run Code Online (Sandbox Code Playgroud)

然后,df["attr2"]仍然有dtype object,虽然type(df["attr2"].ix[0]揭示str,这是正确的.

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

HYR*_*YRY 135

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

这是一个例子:

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

在此输入图像描述

  • 但是请注意,拥有“对象”类型列比对DataFrame读/写操作的性能有重大影响 (3认同)
  • 我可以以某种方式将数据类型作为字符串返回吗?我知道我总是可以使用 type(df["column"].iloc[0]),但它可能是 nan (3认同)

Ben*_*Ben 26

@HYRY 的回答很棒。我只想提供更多背景信息..

数组将数据存储为连续的固定大小的内存块。这些属性的组合使数组的数据访问速度快如闪电。例如,请考虑您的计算机如何存储 32 位整数数组[3,0,1].

在此处输入图片说明

如果您让计算机获取数组中的第三个元素,它将从开头开始,然后跳过 64 位以到达第三个元素。确切知道要跳过多少位是使数组快速的原因

现在考虑字符串序列['hello', 'i', 'am', 'a', 'banana']。字符串是大小不一的对象,所以如果你试图将它们存储在连续的内存块中,它最终看起来像这样。

在此处输入图片说明

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

在此处输入图片说明

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

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

无耻地将我自己的课程插入我最初讨论的NumPy上。

  • @hpy 苹果主题演讲 (4认同)
  • 写得好。。谢谢 (2认同)
  • @Ben:谢谢你的回答。不相关的问题:你是如何在答案中创建图形和动画的??? (2认同)
  • @Ben:酷,谢谢!能够将事物形象化有很大帮助,非常感谢。 (2认同)

fug*_*ede 12

从版本 1.0.0(2020 年 1 月)开始,pandas 引入了一项实验性功能,通过pandas.StringDtype.

虽然默认情况下您仍然会看到,但可以通过指定of或简单地object使用新类型:dtypepd.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
Run Code Online (Sandbox Code Playgroud)

  • 暂时不要使用这个....。正如他们所说,“实施可能会在没有警告的情况下发生变化。”这意味着新的更新将破坏您的旧程序。 (5认同)
  • 从 Pandas 1.1 开始,API 似乎已经稳定 [_所有 dtypes 现在都可以转换为 StringDtype_](https://pandas.pydata.org/pandas-docs/stable/whatsnew/v1.1.0.html#all-dtypes-现在可以转换为 stringdtype)。 (4认同)
  • 好吧,这一切都取决于您要使用它做什么。如果你想在需要持续升级包的生产系统中使用它,并且 API 损坏会导致不可接受的维护负担,那么当然要密切注意“实验性”这个词,但如果你使用 pandas 来执行探索性在脚本中进行分析,其生命周期不会增加工作日,那么这些问题对您来说应该没有什么意义。 (2认同)

The*_*Pea 6

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

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

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

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