Pandas read_csv low_memory和dtype选项

时间:2014-06-16 19:56:48

标签: python parsing numpy pandas dataframe

致电

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

我明白了:

  

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

为什么dtype选项与low_memory相关,为什么让False帮助解决此问题?

10 个答案:

答案 0 :(得分:296)

已弃用的low_memory选项

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

你得到这个low_memory警告的原因是因为猜测每列的dtypes是非常需要内存的。 Pandas试图通过分析每列中的数据来确定要设置的dtype。

Dtype猜测(非常糟糕)

Pandas只能确定读取整个文件后列应该具有什么类型。这意味着在读取整个文件之前无法真正解析任何内容,除非您在读取最后一个值时有必要更改该列的dtype。

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

指定dtypes(应该始终完成)

添加

dtype={'user_id': int}

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

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

定义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": object})

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

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

存在什么dtypes?

这些是pandas

中也接受的numpy dtypes
[numpy.generic,
 [[numpy.number,
   [[numpy.integer,
     [[numpy.signedinteger,
       [numpy.int8,
        numpy.int16,
        numpy.int32,
        numpy.int64,
        numpy.int64,
        numpy.timedelta64]],
      [numpy.unsignedinteger,
       [numpy.uint8,
        numpy.uint16,
        numpy.uint32,
        numpy.uint64,
        numpy.uint64]]]],
    [numpy.inexact,
     [[numpy.floating,
       [numpy.float16, numpy.float32, numpy.float64, numpy.float128]],
      [numpy.complexfloating,
       [numpy.complex64, numpy.complex128, numpy.complex256]]]]]],
  [numpy.flexible,
   [[numpy.character, [numpy.bytes_, numpy.str_]],
    [numpy.void, [numpy.record]]]],
  numpy.bool_,
  numpy.datetime64,
  numpy.object_]]

Pandas还添加了两个douspes:categoricaldatetime64[ns, tz] numpy中不可用

Pandas dtype reference

陷阱,警告,注释

设置dtype=object会使上述警告无效,但不会提高内存效率,只有处理有效。

设置dtype=unicode将无法执行任何操作,因为要将unicode表示为object

转换器的使用

@sparrow正确地指出转换器的使用,以避免在指定为'foobar'的列中遇到int时大熊猫爆炸。我想补充一点,转换器在pandas中使用非常繁重且效率低,应该作为最后的手段使用。这是因为read_csv进程是一个进程。

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

答案 1 :(得分:34)

尝试:

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

根据熊猫文件:

  

dtype:列名称或列表 - >型

至于low_memory,它是真by default,并且还没有记录。我不认为它的相关性。错误消息是通用的,因此您无论如何都不应该使用low_memory。希望这有帮助,如果您有其他问题,请告诉我

答案 2 :(得分:28)

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

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

答案 3 :(得分:12)

如前面提到的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})

答案 4 :(得分:2)

在处理巨大的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 :(得分:1)

在导入DataFrame时,它与low_memory = False一起为我工作。这就是对我有用的所有更改:

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

答案 6 :(得分:0)

我有一个约400MB文件的类似问题。设置low_memory=False为我做了诀窍。首先做一些简单的事情,我会检查你的数据帧是否不比你的系统内存大,重新启动,在继续之前清除RAM。如果您仍然遇到错误,请确保您的.csv文件正常,请快速查看Excel并确保没有明显的损坏。破碎的原始数据可能会造成严重破坏......

答案 7 :(得分:0)

根据pandas documentation,只要low_memory=False(这是默认设置),就指定engine='c'是解决此问题的合理方法。

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

如果low_memory=True(默认设置),则大熊猫以大块行的形式读取数据,然后将它们附加在一起。然后,某些列可能看起来像整数块和字符串块混合在一起,这取决于在该块熊猫期间是否遇到了任何无法转换为整数的事物(例如)。以后可能会引起问题。警告告诉您在读入操作中至少发生过一次,因此请务必小心。设置low_memory=False将使用更多的内存,但可以避免该问题。

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

以下代码说明了一个示例,其中设置了low_memory=True,并且列包含混合类型。它通过@firelynx构建了答案

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 !!!!!

在旁边:举个例子,说明这是一个问题(我第一次遇到的是一个严重问题),假设您在文件上运行pd.read_csv(),然后想根据标识符删除重复项。说标识符有时是数字的,有时是字符串。一行可能是“ 81287”,另一行可能是“ 97324-32”。它们仍然是唯一的标识符。

使用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

答案 8 :(得分:0)

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

file = pd.read_csv('example.csv', dtype='unicode')

答案 9 :(得分:0)

有时候,当其他所有方法都失败时,您只想告诉熊猫就此关闭:

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