当前位置: 首页 > 面试题库 >

从嵌套列表创建DataFrame时可以访问read_csv()的dtype推理引擎吗?

宇文俊明
2023-03-14
问题内容

这是通过在此处与piRSquared进行的讨论得出的,在这里我发现它read_csv似乎具有自己的类型推断方法,这些方法似乎在获取正确类型的能力方面更广泛。在丢失数据的情况下,它似乎更具容错能力,它选择NaN而不是将ValueError其作为默认行为。

在很多情况下,推断的数据类型对于我的工作而言是完全可以接受的,但是在实例化DataFrameAPI或我可以找到的API中的其他任何地方时,似乎并未公开此功能,这意味着我必须进行dtypes不必要的手动处理。如果您有数百列,这可能会很乏味。我能找到的最接近的是,convert_objects()但是在这种情况下,它不能处理布尔值。我可以使用的替代方法是转储到磁盘并读回,这效率很低。

下面的示例说明read_csvv的默认行为与设置dtype的常规方法的默认行为(在V中正确0.20.3)。有没有一种方法可以在read_csv不转储到磁盘的情况下访问类型推断?更普遍地讲,为什么会有这样的read_csv行为?

例:

import numpy as np
import pandas as pd
import csv

data = [['string_boolean', 'numeric', 'numeric_missing'], 
        ['FALSE', 23, 50], 
        ['TRUE', 19, 12], 
        ['FALSE', 4.8, '']]

with open('my_csv.csv', 'w') as outfile:
    writer = csv.writer(outfile)
    writer.writerows(data)

# Reading from CSV
df = pd.read_csv('my_csv.csv')
print(df.string_boolean.dtype) # Automatically converted to bool
print(df.numeric.dtype) # Float, as expected
print(df.numeric_missing.dtype) # Float, doesn't care about empty string

# Creating directly from list without supplying datatypes
df2 = pd.DataFrame(data[1:], columns=data[0])
df2.string_boolean = df2.string_boolean.astype(bool) # Doesn't work - ValueError
df2.numeric_missing = df2.numeric_missing.astype(np.float64) # Doesn't work

# Creating but forcing dtype doesn't work
df3 = pd.DataFrame(data[1:], columns=data[0], 
                   dtype=[bool, np.float64, np.float64])

# The working method
df4 = pd.DataFrame(data[1:], columns=data[0])
df4.string_boolean.map({'TRUE': True, 'FALSE': False})
df4.numeric_missing = pd.to_numeric(df4.numeric_missing)

问题答案:

一种解决方案是使用StringIO对象。唯一的区别是,它将所有数据保留在内存中,而不是写入磁盘并回读。

代码如下(注意:Python 3!):

import numpy as np
import pandas as pd
import csv
from io import StringIO

data = [['string_boolean', 'numeric', 'numeric_missing'],
        ['FALSE', 23, 50],
        ['TRUE', 19, 12],
        ['FALSE', 4.8, '']]

with StringIO() as fobj:
    writer = csv.writer(fobj)
    writer.writerows(data)
    fobj.seek(0)
    df = pd.read_csv(fobj)

print(df.head(3))
print(df.string_boolean.dtype) # Automatically converted to bool
print(df.numeric.dtype) # Float, as expected
print(df.numeric_missing.dtype) # Float, doesn't care about empty string

with StringIO() as fobj是不是真的有必要:fobj = String()将工作一样很好。并且由于上下文管理器将在StringIO()对象范围之外关闭对象,因此df = pd.read_csv(fobj)必须在对象内部。
还要注意fobj.seek(0),这是另一个必要条件,因为您的解决方案只是关闭并重新打开文件,这将自动将文件指针设置为文件的开头。

关于Python 2与Python 3的说明

我实际上试图使以上代码与Python 2/3兼容。由于以下原因,这变得一团糟:Python 2具有一个io模块,就像Python
3一样,该模块的StringIO类使所有代码都是unicode的(在Python 2中也是如此;在Python 3中,它当然是默认的)。
很好,除了csvPython 2中的writer模块 兼容Unicode。
因此,替代方法是使用(较旧的)Python 2(c)StringIO模块,例如,如下所示:

try:
    from cStringIO import StringIO
except ModuleNotFoundError:  # Python 3
    from io import StringIO

并且在Python 2中将是纯文本,在Python 3中将是unicode。
除非现在cStringIO.StringIO没有上下文管理器,with否则该语句将失败。正如我提到的那样,这并不是真正必要的,但是我使事情尽可能地接近您的原始代码。
换句话说,如果没有可笑的技巧,我找不到一种很好的方法来保持接近原始代码。

我还考虑了完全避免CSV编写器,从而导致:

text = '\n'.join(','.join(str(item).strip("'") for item in items) 
                 for items in data)

with StringIO(text) as fobj:
    df = pd.read_csv(fobj)

也许更整洁(虽然不太清楚), 并且与 Python 2/3兼容。(我不希望它能在csv模块可以处理的所有事情上正常工作,但是在这里它可以正常工作。)

为什么不能pd.DataFrame(...)进行转换?

在这里,我只能推测。

我认为原因是,当输入是Python对象(字典,列表)时,输入是已知的,并由程序员掌握。因此,该输入不太可能包含诸如'FALSE'或的字符串,甚至是不合逻辑的''。相反,它通常包含对象Falsenp.nan(或math.nan),因为程序员已经处理了(字符串)转换。
而对于文件(CSV或其他文件),输入内容可以是任何内容:您的同事可能发送了Excel
CSV文件,或者其他人向您发送了数字CSV文件。我不知道CSV文件的标准化程度,但是您可能需要一些代码来允许例外情况,并且总体上需要将字符串转换为Python(NumPy)格式。

因此,从这种意义上讲,期望pd.DAtaFrame(...)只接受任何内容实际上是不合逻辑的:相反,它 应该 接受格式正确的内容。

您可能会争辩一种采用类似您的列表的便捷方法,但是列表不是CSV文件(它只是一堆字符,包括换行符)。另外,我希望pd.read_csv可以读取大块文件(也许是逐行读取)的选项,如果您用换行符代替它,则会变得更加困难(您不能真正逐行读取该文件,因为您将不得不在换行符上将其拆分,并将所有行都保留在内存中。并且您已经在内存中某个位置(而不是磁盘上)存储了完整的字符串。但是我离题了。

此外,StringIO技巧只是几行以精确地执行此技巧。



 类似资料:
  • 问题内容: 我正在尝试从深度嵌套的JSON字符串创建单个Pandas DataFrame对象。 JSON模式是: 期望的结果 我需要将其展平以产生一张桌子: 第一列是值,其余列是键的值并存储在列表中。 到目前为止,我已经 是一个列表,其中长度等于个人数量,即。df对象只是返回 如何遍历该列表以获取dict值并创建N个不同的列?我应该尝试为该列表创建一个DataFrame ,重塑它的形状,然后用角色

  • 问题内容: 也许有人可以帮助我。我试图将以下ist放到pandas数据框中: 结果应如下所示: 但是我尝试做的所有事情都无法获得预期的结果。我用了这样的东西: 但是然后我松开了_source字段之外的类型。我也尝试与 但是我不知道如何使用字段_source并将其附加到原始数据帧。 有人知道如何做到这一点并达到预期的结果吗? 问题答案: 用途:

  • 问题内容: 我正在尝试从JSON创建嵌套的UL。我能够遍历并从对象中获取数据,但是在构建嵌套UL时遇到了麻烦。我认为’.append’方法放置在错误的位置。生成的LI都分组在一起。我如何创建一个循环(或者也可以用另一种方法)来构建带有正确嵌套的子菜单LI的UL?我曾尝试使用其他类似的帖子来解决我的问题,但是我的数据和代码似乎没有任何意义。对此有些不解之举- 我尝试了几种方法来创建此动态列表,但到目

  • 我正在使用MongoDB-Hadoop连接器读取具有嵌入文档的集合。 例外 scala.matcherror:io.abc.spark.schema.personametadata@31FF5060(类为io.abc.spark.sql.catalyst.catalyst.catalysttypeConverters$structconverters.scala:255)在org.apache.s

  • 问题内容: 我试图在一个内部列表中使用外部列表理解的值: 但是不幸的是,这会引发NameError,因为名称是未知的(尽管外部列表理解指定了该名称)。 这是Python的局限性(尝试过2.7.3和3.2.3)还是有充分的理由解释为什么它不起作用? 是否有计划摆脱限制? 是否有解决方法(可能我没有弄清楚一些不同的语法)来实现我想要的? 问题答案: 您在谈论列表 推导 ,而不是生成器表达式。 您需要交

  • 问题内容: 我已经阅读了从平面csv创建嵌套JSON的内容,但对我而言没有帮助。 我有一个很大的电子表格,它是由Google文档创建的,包含11行和74列(某些列未占用)。 我在Google云端硬盘上创建了一个示例。导出为a时,它看起来像这样: 现在,我想要一个结构,如下所示: 以此类推。 我的理论方法是逐行遍历文件(这是第一个问题:现在每一行等于一行,但有时是几行,因此我需要计算逗号?)。每行等