df = pd.read_csv('somefile.csv')
...给出一个错误:
.../site-packages/pandas/io/parsers.py:1130:DtypeWarning:列(4、5、7、16)具有混合类型。在导入时指定 dtype 选项或设置 low_memory=False。
为什么 dtype
选项与 low_memory
相关,为什么 low_memory=False
会有所帮助?
已弃用的 low_memory 选项
low_memory
选项没有被正确弃用,但它应该被弃用,因为它实际上并没有做任何不同的事情[source]
您收到此 low_memory
警告的原因是因为猜测每列的 dtype 对内存的要求很高。 Pandas 试图通过分析每列中的数据来确定要设置的 dtype。
Dtype猜测(非常糟糕)
Pandas 只能在读取整个文件后确定列应具有的 dtype。这意味着在读取整个文件之前无法真正解析任何内容,除非您冒着在读取最后一个值时必须更改该列的 dtype 的风险。
考虑一个文件的例子,它有一个名为 user_id 的列。它包含 1000 万行,其中 user_id 始终是数字。由于 pandas 无法知道它只是数字,因此它可能会将其保留为原始字符串,直到它读取整个文件。
指定 dtypes(应该总是这样做)
添加
dtype={'user_id': int}
pd.read_csv()
调用将使熊猫知道它何时开始读取文件,这只是整数。
另外值得注意的是,如果文件的最后一行在 user_id
列中写入了 "foobar"
,则如果指定了上述 dtype,加载将崩溃。
定义 dtype 时中断数据的示例
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:
'datetime64[ns, <tz>]'
这是一个时区感知时间戳。
'category' 本质上是一个枚举(由整数键表示的字符串以保存
'period[]' 不要与 timedelta 混淆,这些对象实际上锚定到特定的时间段
'Sparse', 'Sparse[int]', 'Sparse[float]' 用于稀疏数据或'其中有很多洞的数据' 它不是在数据框中保存 NaN 或 None 它省略了对象,节省空间.
“间隔”是一个独立的主题,但它的主要用途是用于索引。 See more here
'Int8'、'Int16'、'Int32'、'Int64'、'UInt8'、'UInt16'、'UInt32'、'UInt64' 都是可以为空的 pandas 特定整数,与 numpy 变体不同。
'string' 是用于处理字符串数据的特定 dtype,并允许访问系列的 .str
属性。
'boolean' 类似于 numpy 'bool' 但它也支持缺失数据。
在此处阅读完整的参考资料:
陷阱、注意事项、注释
设置 dtype=object
将使上述警告静音,但不会提高内存效率,如果有的话,只会提高进程效率。
设置 dtype=unicode
不会做任何事情,因为对于 numpy,unicode
表示为 object
。
转换器的使用
@sparrow 正确指出了转换器的使用,以避免在指定为 int
的列中遇到 'foobar'
时 pandas 爆炸。我想补充一点,在 pandas 中使用转换器确实很重且效率低下,应该作为最后的手段使用。这是因为 read_csv 进程是单个进程。
CSV 文件可以逐行处理,因此可以通过简单地将文件切割成段并运行多个进程来更有效地由多个转换器并行处理,这是 pandas 不支持的。但这是一个不同的故事。
尝试:
dashboard_df = pd.read_csv(p_file, sep=',', error_bad_lines=False, index_col=False, dtype='unicode')
根据熊猫文档:
dtype : 类型名称或列的字典 -> 类型
至于 low_memory,它是 True by default 并且尚未记录。我不认为它相关。错误消息是通用的,因此无论如何您都不需要弄乱low_memory。希望这会有所帮助,如果您还有其他问题,请告诉我
dtype=unicode
产生:NameError: name 'unicode' is not defined
。但是将 unicode
放在引号中(如在 'unicode' 中)似乎有效!
numpy.dtype('unicode')
。当你给 dtype 选项一个字符串时,默认情况下它会尝试通过 numpy.dtype()
工厂强制转换它。指定 'unicode'
实际上不会做任何事情,unicode 只是向上转换为 objects
。您将获得 dtype='object'
df = pd.read_csv('somefile.csv', low_memory=False)
这应该可以解决问题。从 CSV 读取 180 万行时,我得到了完全相同的错误。
正如 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})
这对我有用!
file = pd.read_csv('example.csv', engine='python')
在处理一个巨大的 csv 文件(600 万行)时,我遇到了类似的问题。我遇到了三个问题:
该文件包含奇怪的字符(使用编码修复) 未指定数据类型(使用 dtype 属性修复) 使用上述我仍然遇到一个与 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'] = ''
在导入 DataFrame 时,它对我有用 low_memory = False
。这就是对我有用的所有变化:
df = pd.read_csv('export4_16.csv',low_memory=False)
根据 pandas documentation,只要 engine='c'
(这是默认值)就指定 low_memory=False
是解决此问题的合理方法。
如果为 low_memory=False
,则首先读取整个列,然后确定正确的类型。例如,列将根据需要保存为对象(字符串)以保存信息。
如果为 low_memory=True
(默认值),则 pandas 以行块的形式读取数据,然后将它们附加在一起。然后某些列可能看起来像混合在一起的整数块和字符串,这取决于在块期间 pandas 是否遇到任何无法转换为整数的东西(比如)。这可能会导致以后出现问题。警告告诉你这在读入中至少发生了一次,所以你应该小心。设置 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
,pandas 可能会像这样读取标识符列:
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
正如错误所说,您应该在使用 read_csv()
方法时指定数据类型。所以,你应该写
file = pd.read_csv('example.csv', dtype='unicode')
我对约 400MB 的文件也有类似的问题。设置 low_memory=False
对我有用。首先做简单的事情,我会检查您的数据帧是否大于您的系统内存,重新启动,在继续之前清除 RAM。如果您仍然遇到错误,则值得确保您的 .csv
文件正常,在 Excel 中快速查看并确保没有明显的损坏。损坏的原始数据可能会造成严重破坏...
有时,当所有其他方法都失败时,您只想告诉 pandas 闭嘴:
# Ignore DtypeWarnings from pandas' read_csv
warnings.filterwarnings('ignore', message="^Columns.*")
不定期副业成功案例分享
dtype=object
并没有提高内存效率,除了摆脱错误之外,还有什么理由弄乱它?error_bad_lines=False, warn_bad_lines=True
应该可以解决问题。文档说它只对 C 解析器有效。它还说默认解析器是 None ,这使得很难知道哪个是默认解析器。nrows=100
作为参数读取数据帧,然后执行df.dtypes
以查看您获得的数据类型。但是,当使用这些 dtype 读取整个数据帧时,请务必执行try/except
以便您捕捉到错误的 dtype 猜测。你知道,数据很脏。