Pandas read_csv:low_memory 和 dtype 选项

Pandas read_csv: low_memory and dtype options

提问人:Josh 提问时间:6/17/2014 最后编辑:Mateen UlhaqJosh 更新时间:11/22/2022 访问量:701865

问:

df = pd.read_csv('somefile.csv')

...给出错误:

.../site-packages/pandas/io/parsers.py:1130: DtypeWarning:列 (4,5,7,16) 具有混合类型。指定 dtype 导入时的选项或设置 low_memory=False。

为什么该选项与 相关,为什么可能会有所帮助?dtypelow_memorylow_memory=False

python 解析 numpy pandas 数据帧

评论

11赞 maziar 3/22/2016
我对此警告有疑问。提到的列的索引是从 0 开始的吗?例如,具有混合类型的第 4 列是 df[:,4] 或 df[:,3]
6赞 firelynx 5/24/2017
@maziar读取 CSV 时,默认情况下会创建并使用一个新的从 0 开始的索引。

答:

78赞 hd1 6/17/2014 #1

尝试:

dashboard_df = pd.read_csv(p_file, sep=',', error_bad_lines=False, index_col=False, dtype='unicode')

根据 pandas 文档:

dtype :列 -> 类型的类型名称或字典

至于low_memory,默认情况下是 True,尚未记录。我不认为这无关紧要。错误消息是通用的,因此无论如何您都不需要弄乱low_memory。希望这有帮助,如果您有其他问题,请告诉我

评论

1赞 sedeh 2/20/2015
添加 produced: .但是输入引号(如“unicode”)似乎有效!dtype=unicodeNameError: name 'unicode' is not definedunicode
5赞 firelynx 7/15/2015
@sedeh 您可以将 dtypes 指定为 python 类型或 .当您为 dtype 选项提供字符串时,默认情况下,它将尝试通过工厂强制转换它。指定实际上不会做任何事情,unicode 只是被放大到 .你会得到numpy.dtype('unicode')numpy.dtype()'unicode'objectsdtype='object'
713赞 firelynx 12/2/2014 #2

已弃用的 low_memory 选项

该选项没有被正确弃用,但它应该被弃用,因为它实际上并没有做任何不同的事情[来源low_memory]

收到此警告的原因是,猜测每列的 dtypes 对内存的要求非常高。Pandas 尝试通过分析每列中的数据来确定要设置的 dtype。low_memory

Dtype 猜测(非常糟糕)

Pandas 只有在读取整个文件后才能确定列应该具有什么 dtype。这意味着在读取整个文件之前,实际上无法分析任何内容,除非您在读取最后一个值时必须更改该列的 dtype。

考虑一个文件的例子,该文件有一个名为 user_id 的列。 它包含 1000 万行,其中user_id始终是数字。 由于 pandas 无法知道它只是数字,因此它可能会将其保留为原始字符串,直到它读取整个文件。

指定 dtypes(应始终执行)

添加

dtype={'user_id': int}

对 pd.read_csv() 调用将使 pandas 知道它何时开始读取文件,这只是整数。

另外值得注意的是,如果文件中的最后一行已经写入列中,则如果指定了上述 dtype,则加载将崩溃。"foobar"user_id

定义 dtypes 时中断的损坏数据示例

import pandas as pd
try:
    from StringIO import StringIO
except ImportError:
    from io import StringIO


csvdata = """user_id,username
1,Alice
3,Bob
foobar,Caesar"""
sio = StringIO(csvdata)
pd.read_csv(sio, dtype={"user_id": int, "username": "string"})

ValueError: invalid literal for long() with base 10: 'foobar'

dtypes 通常是一个 numpy 的东西,在这里阅读更多关于它们的信息: http://docs.scipy.org/doc/numpy/reference/generated/numpy.dtype.html

存在哪些 dtypes?

我们可以访问 numpy dtypes:float、int、bool、timedelta64[ns] 和 datetime64[ns]。请注意,numpy 日期/时间 dtypes 无法识别时区。

Pandas 用自己的 dtypes 扩展了这组 dtypes:

'datetime64[ns, <tz>]'这是时区感知时间戳。

'category',它本质上是一个枚举(字符串由整数键表示,以保存

'period[]' 不要与时间增量混淆,这些对象实际上锚定到特定的时间段

'Sparse', 'Sparse[int]', 'Sparse[float]' 用于稀疏数据或 '数据中有很多漏洞' 它不是在数据帧中保存 NaN 或 None,而是省略对象,从而节省空间。

“间隔”本身就是一个主题,但它的主要用途是用于索引。在这里查看更多

'Int8', 'Int16', 'Int32', 'Int64', 'UInt8', 'UInt16', 'UInt32', 'UInt64' 都是特定于 pandas 的整数,可以为 null,这与 numpy 变体不同。

“string”是用于处理字符串数据的特定 dtype,用于访问序列上的属性。.str

'boolean' 类似于 numpy 'bool',但它也支持缺失数据。

在此处阅读完整参考资料:

Pandas dtype 参考

陷阱、警告、注释

设置将使上述警告静音,但不会使其更节省内存,只有处理效率(如果有的话)。dtype=object

设置不会做任何事情,因为对于 numpy,a 表示为 .dtype=unicodeunicodeobject

转换器的使用

@sparrow正确地指出了转换器的用法,以避免在指定为 .我想补充一点,转换器在熊猫中使用真的很重且效率低下,应该作为最后的手段使用。这是因为read_csv进程是单个进程。'foobar'int

CSV 文件可以逐行处理,因此可以通过简单地将文件切成段并运行多个进程来更有效地由多个转换器并行处理,这是 pandas 不支持的。但这是另一回事。

评论

9赞 zthomas.nc 8/31/2016
那么,鉴于设置 a 的内存效率并不高,除了消除错误之外,还有什么理由弄乱它吗?dtype=object
7赞 firelynx 9/1/2016
@zthomas.nc 是的,Pandas 不需要费心测试列中的内容。理论上在加载时节省了一些内存(但加载完成后没有内存),理论上节省了一些 cpu 周期(您不会注意到这一点,因为磁盘 I/O 将是瓶颈。
5赞 sparrow 9/1/2016
“另外值得注意的是,如果文件中的最后一行在user_id列中写了”foobar“,那么如果指定了上述 dtype,加载就会崩溃。” 是否有一些“强制”选项可用于丢弃这一行而不是崩溃?
5赞 firelynx 9/2/2016
@sparrow可能有,但上次我使用它时它有错误。它可能会在最新版本的 pandas 中修复。 应该可以解决问题。文档说它只对 C 解析器有效。它还说默认解析器是 None,这使得很难知道哪个是默认的。error_bad_lines=False, warn_bad_lines=True
9赞 firelynx 12/19/2016
@nealmcb 您可以将 dataframe 作为参数读取,然后查看您获得的 dtypes。但是,在使用这些 dtype 读取整个数据帧时,请务必执行 dtype,以便捕获错误的 dtype 猜测。你知道,数据是肮脏的。nrows=100df.dtypestry/except
64赞 Neal 10/16/2015 #3
df = pd.read_csv('somefile.csv', low_memory=False)

这应该可以解决问题。从 CSV 读取 1.8M 行时,我遇到了完全相同的错误。

评论

91赞 firelynx 1/13/2016
这会使错误静音,但实际上不会更改任何其他内容。
3赞 Sitz Blogz 5/25/2017
我在运行 1.5gb 数据文件时遇到了同样的问题
0赞 vampirekabir 2/3/2021
尝试时显示此错误,C错误:内存不足
1赞 JSVJ 3/22/2021
low_memory = False 到底在做什么?是解决问题还是只是不显示错误消息?
1赞 Richard DiSalvo 12/8/2021
@JSVJ我认为设置 low_memory = False 现在可以解决问题(请参阅我的答案)。似乎有一段时间它会被弃用,但这并没有发生。
23赞 sparrow 9/3/2016 #4

如前所述,firelynx如果明确指定了dtype,并且存在与该dtype不兼容的混合数据,则加载将崩溃。我使用这样的转换器作为解决方法来更改数据类型不兼容的值,以便仍然可以加载数据。

def conv(val):
    if not val:
        return 0    
    try:
        return np.float64(val)
    except:        
        return np.float64(0)

df = pd.read_csv(csv_file,converters={'COL_A':conv,'COL_B':conv})
2赞 Dr Nigel 3/29/2018 #5

我在 ~400MB 文件上遇到了类似的问题。设置对我来说是诀窍。首先做简单的事情,我会检查您的数据帧是否大于您的系统内存,重新启动,清除RAM,然后再继续。如果您仍然遇到错误,值得确保您的文件正常,请在 Excel 中快速查看并确保没有明显的损坏。损坏的原始数据可能会造成严重破坏......low_memory=False.csv

6赞 Rajat Saxena 4/17/2019 #6

它在导入 DataFrame 时对我有用。这就是对我有用的所有变化:low_memory = False

df = pd.read_csv('export4_16.csv',low_memory=False)

评论

0赞 Greg Hilston 8/9/2021
这个答案与下面的答案相同,只是使错误静音,但并没有改变firelynx指出的任何其他内容
7赞 wfolkerts 5/18/2020 #7

我在处理一个巨大的 csv 文件(600 万行)时遇到了类似的问题。我有三个问题:

  1. 该文件包含奇怪的字符(使用编码修复)
  2. 未指定数据类型(使用 dtype 属性修复)
  3. 使用上述方法,我仍然面临一个与无法根据文件名定义的file_format相关的问题(使用 try .. 修复,除了..)
    df = pd.read_csv(csv_file,sep=';', encoding = 'ISO-8859-1',
                     names=['permission','owner_name','group_name','size','ctime','mtime','atime','filename','full_filename'],
                     dtype={'permission':str,'owner_name':str,'group_name':str,'size':str,'ctime':object,'mtime':object,'atime':object,'filename':str,'full_filename':str,'first_date':object,'last_date':object})
    
    try:
        df['file_format'] = [Path(f).suffix[1:] for f in df.filename.tolist()]
    except:
        df['file_format'] = ''
5赞 Richard DiSalvo 7/19/2020 #8

根据 pandas 文档,只要指定(这是默认值)是解决这个问题的合理解决方案。low_memory=Falseengine='c'

如果 ,则将首先读入整个列,然后确定正确的类型。例如,列将根据需要保留为对象(字符串)以保留信息。low_memory=False

如果(默认值),则 pandas 会以行块的形式读取数据,然后将它们追加在一起。然后,某些列可能看起来像是混合在一起的整数块和字符串块,具体取决于在块 pandas 是否遇到任何无法转换为整数的内容(例如)。这可能会在以后引起问题。警告告诉您,这在读入时至少发生过一次,因此您应该小心。设置将使用更多内存,但可以避免问题。low_memory=Truelow_memory=False

就我个人而言,我认为这是一个糟糕的默认设置,但我在一个使用比大型数据集多得多的小型数据集的领域工作,因此便利性比效率更重要。low_memory=True

下面的代码演示了一个示例,其中设置了混合类型,并且列具有混合类型。它通过@firelynxlow_memory=True

import pandas as pd
try:
    from StringIO import StringIO
except ImportError:
    from io import StringIO

# make a big csv data file, following earlier approach by @firelynx
csvdata = """1,Alice
2,Bob
3,Caesar
"""

# we have to replicate the "integer column" user_id many many times to get
# pd.read_csv to actually chunk read. otherwise it just reads 
# the whole thing in one chunk, because it's faster, and we don't get any 
# "mixed dtype" issue. the 100000 below was chosen by experimentation.
csvdatafull = ""
for i in range(100000):
    csvdatafull = csvdatafull + csvdata
csvdatafull =  csvdatafull + "foobar,Cthlulu\n"
csvdatafull = "user_id,username\n" + csvdatafull

sio = StringIO(csvdatafull)
# the following line gives me the warning:
    # C:\Users\rdisa\anaconda3\lib\site-packages\IPython\core\interactiveshell.py:3072: DtypeWarning: Columns (0) have mixed types.Specify dtype option on import or set low_memory=False.
    # interactivity=interactivity, compiler=compiler, result=result)
# but it does not always give me the warning, so i guess the internal workings of read_csv depend on background factors
x = pd.read_csv(sio, low_memory=True) #, dtype={"user_id": int, "username": "string"})

x.dtypes
# this gives:
# Out[69]: 
# user_id     object
# username    object
# dtype: object

type(x['user_id'].iloc[0]) # int
type(x['user_id'].iloc[1]) # int
type(x['user_id'].iloc[2]) # int
type(x['user_id'].iloc[10000]) # int
type(x['user_id'].iloc[299999]) # str !!!! (even though it's a number! so this chunk must have been read in as strings)
type(x['user_id'].iloc[300000]) # str !!!!!

题外话:举个例子,说明这是一个问题(也是我第一次遇到这个问题的严重问题),想象一下你运行了一个文件,然后想根据标识符删除重复项。假设标识符有时是数字,有时是字符串。一行可能是“81287”,另一行可能是“97324-32”。尽管如此,它们仍是唯一标识符。pd.read_csv()

使用 ,pandas 可能会在标识符列中读取如下内容:low_memory=True

81287
81287
81287
81287
81287
"81287"
"81287"
"81287"
"81287"
"97324-32"
"97324-32"
"97324-32"
"97324-32"
"97324-32"

仅仅因为它把东西分块了,所以有时标识符 81287 是一个数字,有时是一个字符串。当我尝试基于此删除重复项时,好吧,

81287 == "81287"
Out[98]: False
5赞 Mahmoud Ragab 8/16/2020 #9

正如错误所说,您应该在使用该方法时指定数据类型。 所以,你应该写read_csv()

file = pd.read_csv('example.csv', dtype='unicode')
7赞 technomage 11/26/2020 #10

有时,当所有其他方法都失败时,你只想告诉熊猫闭嘴:

# Ignore DtypeWarnings from pandas' read_csv                                                                                                                                                                                            
warnings.filterwarnings('ignore', message="^Columns.*")

评论

2赞 smerllo 8/11/2022
这并不能解决问题。它只是隐藏了它
2赞 technomage 8/12/2022
取决于警告本身是否是问题所在。
29赞 Jerald Achaibar 11/15/2021 #11

这对我有用!

file = pd.read_csv('example.csv', engine='python')

评论

0赞 gseattle 1/16/2022
同样在这里,1+百万行,赞赏
1赞 brianlmerritt 1/20/2023
除了添加另一个答案之外,我还发现 sql 导出和任何被 Excel 破坏的东西效果最好file = pd.read_csv('example.csv', encoding='utf-8', engine='python')
0赞 brianlmerritt 1/20/2023
哦,你也可以添加, on_bad_lines='warn'
2赞 Iain Hunter 8/26/2022 #12

在 Jerald Achaibar 给出的答案的基础上,我们可以检测到混合的 Dytpes 警告,并且仅在警告发生时使用较慢的 python 引擎:

import warnings

# Force mixed datatype warning to be a python error so we can catch it and reattempt the 
# load using the slower python engine
warnings.simplefilter('error', pandas.errors.DtypeWarning)
try:
    df = pandas.read_csv(path, sep=sep, encoding=encoding)
except pandas.errors.DtypeWarning:
    df = pandas.read_csv(path, sep=sep, encoding=encoding, engine="python")
1赞 Samuel Calado 11/17/2022 #13

这对我有用!

dashboard_df = pd.read_csv(p_file, sep=';', error_bad_lines=False, index_col=False, dtype='unicode')