Pandas 2.2 中文官方教程和指南(十·一)(1)

简介: Pandas 2.2 中文官方教程和指南(十·一)

IO 工具(文本,CSV,HDF5,…)

原文:pandas.pydata.org/docs/user_guide/io.html

pandas I/O API 是一组顶级reader函数,如pandas.read_csv()通常返回一个 pandas 对象。相应的writer函数是对象方法,如DataFrame.to_csv()。下面是包含可用readerwriter的表格。

格式类型 数据描述 读取器 写入器
文本 CSV read_csv to_csv
文本 定宽文本文件 read_fwf
文本 JSON read_json to_json
文本 HTML read_html to_html
文本 LaTeX Styler.to_latex
文本 XML read_xml to_xml
文本 本地剪贴板 read_clipboard to_clipboard
二进制 MS Excel read_excel to_excel
二进制 OpenDocument read_excel
二进制 HDF5 格式 read_hdf to_hdf
二进制 Feather 格式 read_feather to_feather
二进制 Parquet 格式 read_parquet to_parquet
二进制 ORC 格式 read_orc to_orc
二进制 Stata read_stata to_stata
二进制 SAS read_sas
二进制 SPSS read_spss
二进制 Python Pickle 格式 read_pickle to_pickle
SQL SQL read_sql to_sql
SQL Google BigQuery read_gbq to_gbq

这里是一些 IO 方法的非正式性能比较。

注意

对于使用StringIO类的示例,请确保在 Python 3 中导入它时使用from io import StringIO

CSV & 文本文件

用于读取文本文件(也称为平面文件)的主要函数是 read_csv()。查看食谱以获取一些高级策略。

解析选项

read_csv() 接受以下常见参数:

基本

filepath_or_buffervarious

要么是文件的路径(strpathlib.Path,或 py:py._path.local.LocalPath),URL(包括 http、ftp 和 S3 地址),或具有 read() 方法的任何对象(例如打开的文件或 StringIO)。

sepstr,默认为 read_csv()','read_table()\t

要使用的分隔符。如果 sep 为 None,则 C 引擎无法自动检测分隔符,但 Python 解析引擎可以,这意味着将使用后者,并通过 Python 的内置嗅探工具 csv.Sniffer 自动检测分隔符。此外,长度大于 1 且不同于 '\s+' 的分隔符将被解释为正则表达式,并且还将强制使用 Python 解析引擎。请注意,正则表达式分隔符容易忽略带引号的数据。正则表达式示例:'\\r\\t'

delimiterstr,默认为 None

sep 的替代参数名称。

delim_whitespaceboolean,默认为 False

指定是否使用空格(例如 ' ''\t')作为分隔符。等同于设置 sep='\s+'。如果此选项设置为 True,则不应为 delimiter 参数传递任何内容。

列和索引位置及名称

headerint 或整数列表,默认为 'infer'

用作列名和数据起始位置的行号。默认行为是推断列名:如果没有传递名称,则行为与 header=0 相同,并且列名从文件的第一行推断出来,如果显式传递列名,则行为与 header=None 相同。显式传递 header=0 以能够替换现有名称。

头部可以是指定列的 MultiIndex 的行位置的整数列表,例如 [0,1,3]。未指定的中间行将被跳过(例如在此示例中跳过了 2)。请注意,如果 skip_blank_lines=True,此参数将忽略注释行和空行,因此 header=0 表示数据的第一行而不是文件的第一行。

namesarray-like,默认为 None

要使用的列名列表。如果文件不包含标题行,则应明确传递header=None。此列表中不允许重复项。

index_colint,str,int/str 序列或 False,可选,默认为None

用作DataFrame行标签的列,可以作为字符串名称或列索引给出。如果给出 int/str 序列,则使用 MultiIndex。

注意

可以使用index_col=False来强制 pandas使用第一列作为索引,例如当您有一个每行末尾都有分隔符的格式错误文件时。

None的默认值指示 pandas 进行猜测。如果列标题行中的字段数等于数据文件主体中的字段数,则使用默认索引。如果大于此数,则使用前几列作为索引,以使数据主体中的剩余字段数等于标题中的字段数。

在标题之后的第一行用于确定要放入索引的列数。如果后续行的列数少于第一行,则用NaN填充。

可以通过usecols来避免这种情况。这确保了列按原样获取,而尾随数据被忽略。

usecols 类似列表或可调用对象,默认为None

返回列的子集。如果类似列表,则所有元素必须是位置的(即整数索引到文档列)或与用户在names中提供的列名对应的字符串。如果给出了names,则不考虑文档标题行。例如,一个有效的类似列表usecols参数可以是[0, 1, 2]['foo', 'bar', 'baz']

元素顺序被忽略,因此usecols=[0, 1][1, 0]相同。要从具有保留元素顺序的data实例化数据帧,请使用pd.read_csv(data, usecols=['foo', 'bar'])[['foo', 'bar']]['foo', 'bar']顺序或pd.read_csv(data, usecols=['foo', 'bar'])[['bar', 'foo']]['bar', 'foo']顺序。

如果可调用,则将对列名评估可调用函数,返回可调用函数评估为 True 的名称:

In [1]: import pandas as pd
In [2]: from io import StringIO
In [3]: data = "col1,col2,col3\na,b,1\na,b,2\nc,d,3"
In [4]: pd.read_csv(StringIO(data))
Out[4]: 
 col1 col2  col3
0    a    b     1
1    a    b     2
2    c    d     3
In [5]: pd.read_csv(StringIO(data), usecols=lambda x: x.upper() in ["COL1", "COL3"])
Out[5]: 
 col1  col3
0    a     1
1    a     2
2    c     3 

使用此参数可在使用 c 引擎时获得更快的解析时间和更低的内存使用率。Python 引擎在决定要删除哪些列之前首先加载数据。

通用解析配置

dtype 类型名称或列->类型的字典,默认为None

数据或列的数据类型。例如{'a': np.float64, 'b': np.int32, 'c': 'Int64'} 使用strobject与适当的na_values设置一起使用以保留并不解释数据类型。如果指定了转换器,则将应用转换器,而不是数据类型转换。

1.5.0 版本中的新功能:添加了对 defaultdict 的支持。指定一个 defaultdict 作为输入,其中默认值确定未明确列出的列的数据类型。

dtype_backend{“numpy_nullable”,“pyarrow”},默认为 NumPy 支持的数据帧

要使用的 dtype_backend,例如 DataFrame 是否应具有 NumPy 数组,当设置“numpy_nullable”时,所有具有可为空实现的 dtype 都使用可为空 dtype,如果设置“pyarrow”,则所有 dtype 都使用 pyarrow。

dtype_backends 仍处于实验阶段。

2.0 版本中新增。

engine{'c', 'python', 'pyarrow'}

使用的解析引擎。C 和 pyarrow 引擎速度更快,而 python 引擎目前功能更完整。目前只有 pyarrow 引擎支持多线程。

1.4.0 版本中新增:添加了“pyarrow”引擎作为实验性引擎,并且某些功能不受支持,或者可能无法正常工作。

转换器字典,默认为None

用于转换某些列中值的函数字典。键可以是整数或列标签。

true_values 列表,默认为None

要视为True的值。

false_values 列表,默认为None

要视为False的值。

skipinitialspace 布尔值,默认为False

在分隔符后跳过空格。

skiprows 类似列表或整数,默认为None

要跳过的行号(从 0 开始计数)或要在文件开头跳过的行数(整数)。

如果可调用,则将针对行索引评估可调用函数,如果应跳过该行则返回 True,否则返回 False:

In [6]: data = "col1,col2,col3\na,b,1\na,b,2\nc,d,3"
In [7]: pd.read_csv(StringIO(data))
Out[7]: 
 col1 col2  col3
0    a    b     1
1    a    b     2
2    c    d     3
In [8]: pd.read_csv(StringIO(data), skiprows=lambda x: x % 2 != 0)
Out[8]: 
 col1 col2  col3
0    a    b     2 

skipfooterint,默认为0

要跳过文件底部的行数(与 engine=’c’ 不兼容)。

nrows 整数,默认为None

要读取的文件行数。用于读取大文件的片段。

low_memory 布尔值,默认为True

在块中内部处理文件,导致解析时使用更少的内存,但可能混合类型推断。为确保没有混合类型,要么设置为False,要么使用dtype参数指定类型。请注意,无论如何整个文件都会读入单个DataFrame,使用chunksizeiterator参数以返回分块数据。 (仅适用于 C 解析器)

memory_map 布尔值,默认为 False

如果为filepath_or_buffer提供了文件路径,则直接将文件对象映射到内存,并直接从那里访问数据。使用此选项可以提高性能,因为不再有任何 I/O 开销。

NA 和缺失数据处理

na_values 标量、字符串、类似列表或字典,默认为None

附加字符串识别为 NA/NaN。如果传递了字典,则为每列指定特定的 NA 值。请参见下面的 na values const 以获取默认情况下解释为 NaN 的值列表。

keep_default_na 布尔值,默认为True

是否在解析数据时包括默认的 NaN 值。根据是否传递了na_values,行为如下:

  • 如果keep_default_naTrue,并且指定了na_values,则na_values将附加到用于解析的默认 NaN 值。
  • 如果keep_default_naTrue,并且未指定na_values,则仅使用默认 NaN 值进行解析。
  • 如果keep_default_naFalse,且指定了na_values,则只使用指定的 NaN 值na_values进行解析。
  • 如果keep_default_naFalse,且未指定na_values,则不会将任何字符串解析为 NaN。

请注意,如果传递na_filterFalse,则keep_default_nana_values参数将被忽略。

na_filter 布尔值,默认为True

检测缺失值标记(空字符串和 na_values 的值)。在没有任何 NA 的数据中,传递na_filter=False可以提高读取大文件的性能。

verbose 布尔值,默认为False

指示放置在非数字列中的 NA 值的数量。

skip_blank_lines 布尔值,默认为True

如果为True,则跳过空行而不解释为 NaN 值。

日期时间处理

parse_dates 布尔值或整数列表或名称列表或列表列表或字典,默认为False

  • 如果为True -> 尝试解析索引。
  • 如果[1, 2, 3] -> 尝试将列 1、2、3 分别解析为单独的日期列。
  • 如果[[1, 3]] -> 合并列 1 和 3 并解析为单个日期列。
  • 如果{'foo': [1, 3]} -> 解析列 1、3 为日期,并将结果命名为‘foo’。

注意

存在用于 iso8601 格式日期的快速路径。

infer_datetime_format 布尔值,默认为False

如果为True并且启用了 parse_dates 用于某一列,则尝试推断日期时间格式以加快处理速度。

自 2.0.0 版本起弃用:此参数的严格版本现在是默认值,传递它不会产生任何效果。

keep_date_col 布尔值,默认为False

如果为True并且 parse_dates 指定了组合多个列,则保留原始列。

date_parser 函数,默认为None

用于将一系列字符串列转换为日期时间实例数组的函数。默认使用dateutil.parser.parser进行转换。pandas 将尝试以三种不同的方式调用 date_parser,如果发生异常,则继续下一个:1) 将一个或多个数组(由 parse_dates 定义)作为参数传递;2) 将由 parse_dates 定义的列中的字符串值(按行)连接成单个数组并传递;3) 对每一行使用一个或多个字符串(对应于由 parse_dates 定义的列)调用 date_parser。

自 2.0.0 版本起弃用:改用date_format,或者读取为object,然后根据需要应用to_datetime()

date_format 字符串或列->格式字典,默认为None

如果与parse_dates一起使用,将根据此格式解析日期。对于更复杂的情况,请按照object读取,然后根据需要应用to_datetime()

2.0.0 版本中的新功能。

dayfirst 布尔值,默认为False

DD/MM 格式日期,国际和欧洲格式。

cache_dates 布尔值,默认为 True

如果为 True,则使用唯一的转换日期缓存来应用日期时间转换。在解析重复日期字符串时可能会产生显著的加速,特别是带有时区偏移的日期字符串。

迭代

迭代器布尔值,默认为False

返回用于迭代或使用get_chunk()获取块的TextFileReader对象。

块大小整数,默认为None

返回用于迭代的TextFileReader对象。参见下面的迭代和分块。

引用、压缩和文件格式

压缩{'infer', 'gzip', 'bz2', 'zip', 'xz', 'zstd', None, dict},默认为'infer'

用于在磁盘数据的即时解压缩。如果为‘infer’,则如果filepath_or_buffer是以‘.gz’、‘.bz2’、‘.zip’、‘.xz’、‘.zst’结尾的路径,则使用 gzip、bz2、zip、xz 或 zstandard,否则不进行解压缩。如果使用'zip',ZIP 文件必须只包含一个要读取的数据文件。设置为None表示不进行解压缩。也可以是一个字典,其中键'method'设置为其中之一{'zip', 'gzip', 'bz2', 'zstd},其他键值对转发到zipfile.ZipFilegzip.GzipFilebz2.BZ2Filezstandard.ZstdDecompressor。例如,可以传递以下内容以获得更快的压缩和创建可重现的 gzip 存档:compression={'method': 'gzip', 'compresslevel': 1, 'mtime': 1}

从版本 1.2.0 更改:以前的版本将‘gzip’的字典条目转发到gzip.open

千位分隔符字符串,默认为None

千位分隔符。

十进制字符串,默认为'.'

用于识别为小数点的字符。例如,对于欧洲数据使用','

浮点精度字符串,默认为 None

指定 C 引擎应使用哪个转换器处理浮点值。选项为None表示普通转换器,high表示高精度转换器,round_trip表示往返转换器。

行终止符字符串(长度为 1),默认为None

用于将文件分成行的字符。仅与 C 解析器有效。

引用字符字符串(长度为 1)

用于表示引用项的起始和结束的字符。引用项可以包括分隔符,它将被忽略。

引用 int 或csv.QUOTE_*实例,默认为0

控制字段引用行为的csv.QUOTE_*常量。使用QUOTE_MINIMAL(0)、QUOTE_ALL(1)、QUOTE_NONNUMERIC(2)或QUOTE_NONE(3)中的一个。

双引号布尔值,默认为True

当指定quotechar并且quoting不是QUOTE_NONE时,指示是否将字段内两个连续的quotechar元素解释为单个quotechar元素。

转义字符字符串(长度为 1),默认为None

在引用方式为QUOTE_NONE时用于转义分隔符的单字符字符串。

注释字符串,默认为None

指示不应解析行的其余部分。如果在行的开头找到,整行将被完全忽略。此参数必须是单个字符。与空行一样(只要skip_blank_lines=True),完全注释的行由参数header忽略,但不由skiprows忽略。例如,如果comment='#',使用header=0解析‘#empty\na,b,c\n1,2,3’将导致���a,b,c’被视为标题。

encodingstr,默认为None

读取/写入 UTF 时要使用的编码(例如,'utf-8')。Python 标准编码列表

dialectstr 或csv.Dialect实例,默认为None

如果提供,此参数将覆盖以下参数的值(默认或非默认):delimiterdoublequoteescapecharskipinitialspacequotecharquoting。如果需要覆盖值,将发出 ParserWarning。有关更多详细信息,请参阅csv.Dialect文档。

错误处理

on_bad_lines(‘error’、‘warn’、‘skip’),默认为‘error’

指定在遇到坏行(字段过多的行)时要执行的操作。允许的值为:

  • ‘error’,遇到坏行时引发 ParserError。
  • ‘warn’,遇到坏行时打印警告并跳过该行。
  • ‘skip’,遇到坏行时跳过而不引发或警告。

1.3.0 版中的新功能。

指定列数据类型

您可以指示整个DataFrame或单独的列的数据类型:

In [9]: import numpy as np
In [10]: data = "a,b,c,d\n1,2,3,4\n5,6,7,8\n9,10,11"
In [11]: print(data)
a,b,c,d
1,2,3,4
5,6,7,8
9,10,11
In [12]: df = pd.read_csv(StringIO(data), dtype=object)
In [13]: df
Out[13]: 
 a   b   c    d
0  1   2   3    4
1  5   6   7    8
2  9  10  11  NaN
In [14]: df["a"][0]
Out[14]: '1'
In [15]: df = pd.read_csv(StringIO(data), dtype={"b": object, "c": np.float64, "d": "Int64"})
In [16]: df.dtypes
Out[16]: 
a      int64
b     object
c    float64
d      Int64
dtype: object 

幸运的是,pandas 提供了多种方法来确保您的列只包含一个dtype。如果您对这些概念不熟悉,可以查看这里了解有关 dtypes 的更多信息,以及这里了解有关 pandas 中object转换的更多信息。

例如,您可以使用read_csv()converters参数:

In [17]: data = "col_1\n1\n2\n'A'\n4.22"
In [18]: df = pd.read_csv(StringIO(data), converters={"col_1": str})
In [19]: df
Out[19]: 
 col_1
0     1
1     2
2   'A'
3  4.22
In [20]: df["col_1"].apply(type).value_counts()
Out[20]: 
col_1
<class 'str'>    4
Name: count, dtype: int64 

或者您可以在读取数据后使用to_numeric()函数强制转换 dtypes,

In [21]: df2 = pd.read_csv(StringIO(data))
In [22]: df2["col_1"] = pd.to_numeric(df2["col_1"], errors="coerce")
In [23]: df2
Out[23]: 
 col_1
0   1.00
1   2.00
2    NaN
3   4.22
In [24]: df2["col_1"].apply(type).value_counts()
Out[24]: 
col_1
<class 'float'>    4
Name: count, dtype: int64 

这将将所有有效解析转换为浮点数,将无效解析保留为NaN

最终,如何处理包含混合 dtypes 的列取决于您的具体需求。在上面的情况下,如果您想要将数据异常值设置为NaN,那么to_numeric()可能是您最好的选择。然而,如果您希望所有数据被强制转换,无论类型如何,那么使用read_csv()converters参数肯定值得一试。

注意

在某些情况下,读取包含混合 dtype 列的异常数据将导致数据集不一致。如果依赖 pandas 推断列的 dtype,解析引擎将会推断数据的不同块的 dtype,而不是一次推断整个数据集。因此,可能会出现具有混合 dtype 的列。例如,

In [25]: col_1 = list(range(500000)) + ["a", "b"] + list(range(500000))
In [26]: df = pd.DataFrame({"col_1": col_1})
In [27]: df.to_csv("foo.csv")
In [28]: mixed_df = pd.read_csv("foo.csv")
In [29]: mixed_df["col_1"].apply(type).value_counts()
Out[29]: 
col_1
<class 'int'>    737858
<class 'str'>    262144
Name: count, dtype: int64
In [30]: mixed_df["col_1"].dtype
Out[30]: dtype('O') 

将导致mixed_df包含某些列块的int dtype,以及由于读取的数据中混合 dtype 而导致其他列块的str。重要的是要注意,整体列将被标记为objectdtype,用于具有混合 dtype 的列。

设置dtype_backend="numpy_nullable"将导致每列具有可空 dtype。

In [31]: data = """a,b,c,d,e,f,g,h,i,j
 ....: 1,2.5,True,a,,,,,12-31-2019,
 ....: 3,4.5,False,b,6,7.5,True,a,12-31-2019,
 ....: """
 ....: 
In [32]: df = pd.read_csv(StringIO(data), dtype_backend="numpy_nullable", parse_dates=["i"])
In [33]: df
Out[33]: 
 a    b      c  d     e     f     g     h          i     j
0  1  2.5   True  a  <NA>  <NA>  <NA>  <NA> 2019-12-31  <NA>
1  3  4.5  False  b     6   7.5  True     a 2019-12-31  <NA>
In [34]: df.dtypes
Out[34]: 
a             Int64
b           Float64
c           boolean
d    string[python]
e             Int64
f           Float64
g           boolean
h    string[python]
i    datetime64[ns]
j             Int64
dtype: object 
```### 指定分类 dtype
`Categorical`列可以直接通过指定`dtype='category'`或`dtype=CategoricalDtype(categories, ordered)`来解析。
```py
In [35]: data = "col1,col2,col3\na,b,1\na,b,2\nc,d,3"
In [36]: pd.read_csv(StringIO(data))
Out[36]: 
 col1 col2  col3
0    a    b     1
1    a    b     2
2    c    d     3
In [37]: pd.read_csv(StringIO(data)).dtypes
Out[37]: 
col1    object
col2    object
col3     int64
dtype: object
In [38]: pd.read_csv(StringIO(data), dtype="category").dtypes
Out[38]: 
col1    category
col2    category
col3    category
dtype: object 

可以使用字典规范将单独的列解析为Categorical

In [39]: pd.read_csv(StringIO(data), dtype={"col1": "category"}).dtypes
Out[39]: 
col1    category
col2      object
col3       int64
dtype: object 

指定dtype='category'将导致一个无序的Categorical,其categories是数据中观察到的唯一值。要对类别和顺序进行更多控制,预先创建一个CategoricalDtype,并将其传递给该列的dtype

In [40]: from pandas.api.types import CategoricalDtype
In [41]: dtype = CategoricalDtype(["d", "c", "b", "a"], ordered=True)
In [42]: pd.read_csv(StringIO(data), dtype={"col1": dtype}).dtypes
Out[42]: 
col1    category
col2      object
col3       int64
dtype: object 

使用dtype=CategoricalDtype时,dtype.categories之外的“意外”值被视为缺失值。

In [43]: dtype = CategoricalDtype(["a", "b", "d"])  # No 'c'
In [44]: pd.read_csv(StringIO(data), dtype={"col1": dtype}).col1
Out[44]: 
0      a
1      a
2    NaN
Name: col1, dtype: category
Categories (3, object): ['a', 'b', 'd'] 

这与Categorical.set_categories()的行为相匹配。

注意

使用dtype='category',生成的类别将始终被解析为字符串(对象 dtype)。如果类别是数字的,可以使用to_numeric()函数进行转换,或者根据需要使用另一个转换器,如to_datetime()

dtype是具有同质categories(全部是数字,全部是日期时间等)的CategoricalDtype时,转换会自动完成。

In [45]: df = pd.read_csv(StringIO(data), dtype="category")
In [46]: df.dtypes
Out[46]: 
col1    category
col2    category
col3    category
dtype: object
In [47]: df["col3"]
Out[47]: 
0    1
1    2
2    3
Name: col3, dtype: category
Categories (3, object): ['1', '2', '3']
In [48]: new_categories = pd.to_numeric(df["col3"].cat.categories)
In [49]: df["col3"] = df["col3"].cat.rename_categories(new_categories)
In [50]: df["col3"]
Out[50]: 
0    1
1    2
2    3
Name: col3, dtype: category
Categories (3, int64): [1, 2, 3] 

命名和使用列

处理列名

文件可能有或没有标题行。pandas 假定第一行应该用作列名:

In [51]: data = "a,b,c\n1,2,3\n4,5,6\n7,8,9"
In [52]: print(data)
a,b,c
1,2,3
4,5,6
7,8,9
In [53]: pd.read_csv(StringIO(data))
Out[53]: 
 a  b  c
0  1  2  3
1  4  5  6
2  7  8  9 

通过在header中与names参数结合使用,可以指示要使用的其他名称以及是否丢弃标题行(如果有):

In [54]: print(data)
a,b,c
1,2,3
4,5,6
7,8,9
In [55]: pd.read_csv(StringIO(data), names=["foo", "bar", "baz"], header=0)
Out[55]: 
 foo  bar  baz
0    1    2    3
1    4    5    6
2    7    8    9
In [56]: pd.read_csv(StringIO(data), names=["foo", "bar", "baz"], header=None)
Out[56]: 
 foo bar baz
0   a   b   c
1   1   2   3
2   4   5   6
3   7   8   9 

如果标题在第一行之外的行中,将行号传递给header。这将跳过前面的行:

In [57]: data = "skip this skip it\na,b,c\n1,2,3\n4,5,6\n7,8,9"
In [58]: pd.read_csv(StringIO(data), header=1)
Out[58]: 
 a  b  c
0  1  2  3
1  4  5  6
2  7  8  9 

注意

默认行为是推断列名:如果没有传递列名,则行为与header=0相同,并且列名是从文件的第一行非空行推断出来的,如果显式传递了列名,则行为与header=None相同。 ### 重复名称解析

如果文件或标题包含重复的名称,pandas 默认会区分它们,以防止数据被覆盖:

In [59]: data = "a,b,a\n0,1,2\n3,4,5"
In [60]: pd.read_csv(StringIO(data))
Out[60]: 
 a  b  a.1
0  0  1    2
1  3  4    5 

不再有重复数据,因为重复列‘X’,…,‘X’变为‘X’,‘X.1’,…,‘X.N’。

过滤列(usecols

usecols参数允许您选择文件中任意列的子集,可以使用列名、位置编号或可调用对象:

In [61]: data = "a,b,c,d\n1,2,3,foo\n4,5,6,bar\n7,8,9,baz"
In [62]: pd.read_csv(StringIO(data))
Out[62]: 
 a  b  c    d
0  1  2  3  foo
1  4  5  6  bar
2  7  8  9  baz
In [63]: pd.read_csv(StringIO(data), usecols=["b", "d"])
Out[63]: 
 b    d
0  2  foo
1  5  bar
2  8  baz
In [64]: pd.read_csv(StringIO(data), usecols=[0, 2, 3])
Out[64]: 
 a  c    d
0  1  3  foo
1  4  6  bar
2  7  9  baz
In [65]: pd.read_csv(StringIO(data), usecols=lambda x: x.upper() in ["A", "C"])
Out[65]: 
 a  c
0  1  3
1  4  6
2  7  9 

usecols参数也可以用于指定最终结果中不使用的列:

In [66]: pd.read_csv(StringIO(data), usecols=lambda x: x not in ["a", "c"])
Out[66]: 
 b    d
0  2  foo
1  5  bar
2  8  baz 

在这种情况下,可调用对象指定我们从输出中排除“a”和“c”列。

注释和空行

忽略行注释和空行

如果指定了comment参数,则完全注释的行将被忽略。默认情况下,完全空白行也将被忽略。

In [67]: data = "\na,b,c\n  \n# commented line\n1,2,3\n\n4,5,6"
In [68]: print(data)
a,b,c
# commented line
1,2,3
4,5,6
In [69]: pd.read_csv(StringIO(data), comment="#")
Out[69]: 
 a  b  c
0  1  2  3
1  4  5  6 

如果skip_blank_lines=False,那么read_csv将不会忽略空行:

In [70]: data = "a,b,c\n\n1,2,3\n\n\n4,5,6"
In [71]: pd.read_csv(StringIO(data), skip_blank_lines=False)
Out[71]: 
 a    b    c
0  NaN  NaN  NaN
1  1.0  2.0  3.0
2  NaN  NaN  NaN
3  NaN  NaN  NaN
4  4.0  5.0  6.0 

警告

忽略行的存在可能会导致涉及行号的歧义;参数header使用行号(忽略注释/空行),而skiprows使用行号(包括注释/空行):

In [72]: data = "#comment\na,b,c\nA,B,C\n1,2,3"
In [73]: pd.read_csv(StringIO(data), comment="#", header=1)
Out[73]: 
 A  B  C
0  1  2  3
In [74]: data = "A,B,C\n#comment\na,b,c\n1,2,3"
In [75]: pd.read_csv(StringIO(data), comment="#", skiprows=2)
Out[75]: 
 a  b  c
0  1  2  3 

如果同时指定了headerskiprowsheader将相对于skiprows的末尾。例如:

In [76]: data = (
 ....:    "# empty\n"
 ....:    "# second empty line\n"
 ....:    "# third emptyline\n"
 ....:    "X,Y,Z\n"
 ....:    "1,2,3\n"
 ....:    "A,B,C\n"
 ....:    "1,2.,4.\n"
 ....:    "5.,NaN,10.0\n"
 ....: )
 ....: 
In [77]: print(data)
# empty
# second empty line
# third emptyline
X,Y,Z
1,2,3
A,B,C
1,2.,4.
5.,NaN,10.0
In [78]: pd.read_csv(StringIO(data), comment="#", skiprows=4, header=1)
Out[78]: 
 A    B     C
0  1.0  2.0   4.0
1  5.0  NaN  10.0 
```#### 注释
有时文件中可能包含注释或元数据:
```py
In [79]: data = (
 ....:    "ID,level,category\n"
 ....:    "Patient1,123000,x # really unpleasant\n"
 ....:    "Patient2,23000,y # wouldn't take his medicine\n"
 ....:    "Patient3,1234018,z # awesome"
 ....: )
 ....: 
In [80]: with open("tmp.csv", "w") as fh:
 ....:    fh.write(data)
 ....: 
In [81]: print(open("tmp.csv").read())
ID,level,category
Patient1,123000,x # really unpleasant
Patient2,23000,y # wouldn't take his medicine
Patient3,1234018,z # awesome 

默认情况下,解析器会将注释包含在输出中:

In [82]: df = pd.read_csv("tmp.csv")
In [83]: df
Out[83]: 
 ID    level                        category
0  Patient1   123000           x # really unpleasant
1  Patient2    23000  y # wouldn't take his medicine
2  Patient3  1234018                     z # awesome 

我们可以使用comment关键字来抑制注释:

In [84]: df = pd.read_csv("tmp.csv", comment="#")
In [85]: df
Out[85]: 
 ID    level category
0  Patient1   123000       x 
1  Patient2    23000       y 
2  Patient3  1234018       z 
```### 处理 Unicode 数据
应该使用`encoding`参数来处理编码的 Unicode 数据,这将导致字节字符串在结果中被解码为 Unicode:
```py
In [86]: from io import BytesIO
In [87]: data = b"word,length\n" b"Tr\xc3\xa4umen,7\n" b"Gr\xc3\xbc\xc3\x9fe,5"
In [88]: data = data.decode("utf8").encode("latin-1")
In [89]: df = pd.read_csv(BytesIO(data), encoding="latin-1")
In [90]: df
Out[90]: 
 word  length
0  Träumen       7
1    Grüße       5
In [91]: df["word"][1]
Out[91]: 'Grüße' 

一些将所有字符编码为多字节的格式,如 UTF-16,如果不指定编码,则根本无法正确解析。Python 标准编码的完整列表。 ### 索引列和尾随分隔符

如果文件的数据列比列名多一个,第一列将被用作DataFrame的行名:

In [92]: data = "a,b,c\n4,apple,bat,5.7\n8,orange,cow,10"
In [93]: pd.read_csv(StringIO(data))
Out[93]: 
 a    b     c
4   apple  bat   5.7
8  orange  cow  10.0 
In [94]: data = "index,a,b,c\n4,apple,bat,5.7\n8,orange,cow,10"
In [95]: pd.read_csv(StringIO(data), index_col=0)
Out[95]: 
 a    b     c
index 
4       apple  bat   5.7
8      orange  cow  10.0 

通常情况下,您可以使用index_col选项来实现这种行为。

在某些异常情况下,文件在每个数据行末尾都有分隔符,这会使解析器混淆。要显式禁用索引列推断并丢弃最后一列,请传入index_col=False

In [96]: data = "a,b,c\n4,apple,bat,\n8,orange,cow,"
In [97]: print(data)
a,b,c
4,apple,bat,
8,orange,cow,
In [98]: pd.read_csv(StringIO(data))
Out[98]: 
 a    b   c
4   apple  bat NaN
8  orange  cow NaN
In [99]: pd.read_csv(StringIO(data), index_col=False)
Out[99]: 
 a       b    c
0  4   apple  bat
1  8  orange  cow 

如果正在使用usecols选项解析数据的子集,则index_col规范是基于该子集而不是原始数据的。

In [100]: data = "a,b,c\n4,apple,bat,\n8,orange,cow,"
In [101]: print(data)
a,b,c
4,apple,bat,
8,orange,cow,
In [102]: pd.read_csv(StringIO(data), usecols=["b", "c"])
Out[102]: 
 b   c
4  bat NaN
8  cow NaN
In [103]: pd.read_csv(StringIO(data), usecols=["b", "c"], index_col=0)
Out[103]: 
 b   c
4  bat NaN
8  cow NaN 
```### 日期处理
#### 指定日期列
为了更好地处理日期时间数据,`read_csv()`使用关键字参数`parse_dates`和`date_format`,允许用户指定各种列和日期/时间格式,将输入文本数据转换为`datetime`对象。
最简单的情况是只传入`parse_dates=True`:
```py
In [104]: with open("foo.csv", mode="w") as f:
 .....:    f.write("date,A,B,C\n20090101,a,1,2\n20090102,b,3,4\n20090103,c,4,5")
 .....: 
# Use a column as an index, and parse it as dates.
In [105]: df = pd.read_csv("foo.csv", index_col=0, parse_dates=True)
In [106]: df
Out[106]: 
 A  B  C
date 
2009-01-01  a  1  2
2009-01-02  b  3  4
2009-01-03  c  4  5
# These are Python datetime objects
In [107]: df.index
Out[107]: DatetimeIndex(['2009-01-01', '2009-01-02', '2009-01-03'], dtype='datetime64[ns]', name='date', freq=None) 

通常情况下,我们可能希望将日期和时间数据分开存储,或将各种日期字段分开存储。parse_dates关键字可用于指定要从中解析日期和/或时间的列的组合。

您可以将列列表的列表指定为 parse_dates,生成的日期列将被添加到输出中(以不影响现有列顺序),新列名将是组件列名的连接:

In [108]: data = (
 .....:    "KORD,19990127, 19:00:00, 18:56:00, 0.8100\n"
 .....:    "KORD,19990127, 20:00:00, 19:56:00, 0.0100\n"
 .....:    "KORD,19990127, 21:00:00, 20:56:00, -0.5900\n"
 .....:    "KORD,19990127, 21:00:00, 21:18:00, -0.9900\n"
 .....:    "KORD,19990127, 22:00:00, 21:56:00, -0.5900\n"
 .....:    "KORD,19990127, 23:00:00, 22:56:00, -0.5900"
 .....: )
 .....: 
In [109]: with open("tmp.csv", "w") as fh:
 .....:    fh.write(data)
 .....: 
In [110]: df = pd.read_csv("tmp.csv", header=None, parse_dates=[[1, 2], [1, 3]])
In [111]: df
Out[111]: 
 1_2                 1_3     0     4
0 1999-01-27 19:00:00 1999-01-27 18:56:00  KORD  0.81
1 1999-01-27 20:00:00 1999-01-27 19:56:00  KORD  0.01
2 1999-01-27 21:00:00 1999-01-27 20:56:00  KORD -0.59
3 1999-01-27 21:00:00 1999-01-27 21:18:00  KORD -0.99
4 1999-01-27 22:00:00 1999-01-27 21:56:00  KORD -0.59
5 1999-01-27 23:00:00 1999-01-27 22:56:00  KORD -0.59 

默认情况下,解析器会删除组件日期列,但您可以通过 keep_date_col 关键字选择保留它们:

In [112]: df = pd.read_csv(
 .....:    "tmp.csv", header=None, parse_dates=[[1, 2], [1, 3]], keep_date_col=True
 .....: )
 .....: 
In [113]: df
Out[113]: 
 1_2                 1_3     0  ...          2          3     4
0 1999-01-27 19:00:00 1999-01-27 18:56:00  KORD  ...   19:00:00   18:56:00  0.81
1 1999-01-27 20:00:00 1999-01-27 19:56:00  KORD  ...   20:00:00   19:56:00  0.01
2 1999-01-27 21:00:00 1999-01-27 20:56:00  KORD  ...   21:00:00   20:56:00 -0.59
3 1999-01-27 21:00:00 1999-01-27 21:18:00  KORD  ...   21:00:00   21:18:00 -0.99
4 1999-01-27 22:00:00 1999-01-27 21:56:00  KORD  ...   22:00:00   21:56:00 -0.59
5 1999-01-27 23:00:00 1999-01-27 22:56:00  KORD  ...   23:00:00   22:56:00 -0.59
[6 rows x 7 columns] 

请注意,如果您希望将多个列合并为单个日期列,则必须使用嵌套列表。换句话说,parse_dates=[1, 2] 表示应将第二和第三列分别解析为单独的日期列,而 parse_dates=[[1, 2]] 表示应将这两列解析为单个列。

您还可以使用字典指定自定义列名:

In [114]: date_spec = {"nominal": [1, 2], "actual": [1, 3]}
In [115]: df = pd.read_csv("tmp.csv", header=None, parse_dates=date_spec)
In [116]: df
Out[116]: 
 nominal              actual     0     4
0 1999-01-27 19:00:00 1999-01-27 18:56:00  KORD  0.81
1 1999-01-27 20:00:00 1999-01-27 19:56:00  KORD  0.01
2 1999-01-27 21:00:00 1999-01-27 20:56:00  KORD -0.59
3 1999-01-27 21:00:00 1999-01-27 21:18:00  KORD -0.99
4 1999-01-27 22:00:00 1999-01-27 21:56:00  KORD -0.59
5 1999-01-27 23:00:00 1999-01-27 22:56:00  KORD -0.59 

重要的是要记住,如果要将多个文本列解析为单个日期列,则会在数据前添加一个新列。index_col 规范是基于这组新列而不是原始数据列的:

In [117]: date_spec = {"nominal": [1, 2], "actual": [1, 3]}
In [118]: df = pd.read_csv(
 .....:    "tmp.csv", header=None, parse_dates=date_spec, index_col=0
 .....: )  # index is the nominal column
 .....: 
In [119]: df
Out[119]: 
 actual     0     4
nominal 
1999-01-27 19:00:00 1999-01-27 18:56:00  KORD  0.81
1999-01-27 20:00:00 1999-01-27 19:56:00  KORD  0.01
1999-01-27 21:00:00 1999-01-27 20:56:00  KORD -0.59
1999-01-27 21:00:00 1999-01-27 21:18:00  KORD -0.99
1999-01-27 22:00:00 1999-01-27 21:56:00  KORD -0.59
1999-01-27 23:00:00 1999-01-27 22:56:00  KORD -0.59 

请注意

如果列或索引包含无法解析的日期,则整个列或索引将以对象数据类型不变返回。对于非标准日期时间解析,请在 pd.read_csv 后使用 to_datetime()

请注意

read_csv 在解析 iso8601 格式的日期时间字符串(例如“2000-01-01T00:01:02+00:00”及类似变体)时具有快速路径。如果您可以安排数据以这种格式存储日期时间,加载时间将显著加快,观察到的速度提升约为 20 倍。

自版本 2.2.0 起已弃用:在 read_csv 中合并日期列已弃用。请改为在相关结果列上使用 pd.to_datetime

日期解析函数

最后,解析器允许您指定自定义的 date_format。就性能而言,您应该按照以下顺序尝试这些日期解析方法:

  1. 如果您知道格式,请使用 date_format,例如:date_format="%d/%m/%Y"date_format={column_name: "%d/%m/%Y"}
  2. 如果不同列有不同格式,或者想要向 to_datetime 传递任何额外选项(如 utc),则应以 object 类型读取数据,然后使用 to_datetime
解析具有混合时区的 CSV

pandas 无法原生表示具有混合时区的列或索引。如果您的 CSV 文件包含具有混合时区的列,则默认结果将是一个对象类型的列,其中包含字符串,即使使用 parse_dates 也是如此。要将混合时区值解析为日期时间列,请以 object 类型读取,然后调用 to_datetime() 并设置 utc=True

In [120]: content = """\
 .....: a
 .....: 2000-01-01T00:00:00+05:00
 .....: 2000-01-01T00:00:00+06:00"""
 .....: 
In [121]: df = pd.read_csv(StringIO(content))
In [122]: df["a"] = pd.to_datetime(df["a"], utc=True)
In [123]: df["a"]
Out[123]: 
0   1999-12-31 19:00:00+00:00
1   1999-12-31 18:00:00+00:00
Name: a, dtype: datetime64[ns, UTC] 
```#### 推断日期时间格式
以下是一些可以猜测的日期时间字符串示例(均表示 2011 年 12 月 30 日 00:00:00):
+   “20111230”
+   “2011/12/30”
+   “20111230 00:00:00”
+   “12/30/2011 00:00:00”
+   “30/Dec/2011 00:00:00”
+   “30/December/2011 00:00:00”
请注意,格式推断对 `dayfirst` 敏感。当 `dayfirst=True` 时,它会猜测“01/12/2011”是 12 月 1 日。当 `dayfirst=False`(默认)时,它会猜测“01/12/2011”是 1 月 12 日。
如果尝试解析日期字符串列,pandas 将尝试从第一个非 NaN 元素猜测格式,然后使用该格式解析列的其余部分。如果 pandas 无法猜测格式(例如,如果你的第一个字符串是 `'01 December US/Pacific 2000'`),那么将会发出警告,并且每一行将通过 `dateutil.parser.parse` 单独解析。解析日期的最安全方式是明确设置 `format=`。
```py
In [124]: df = pd.read_csv(
 .....:    "foo.csv",
 .....:    index_col=0,
 .....:    parse_dates=True,
 .....: )
 .....: 
In [125]: df
Out[125]: 
 A  B  C
date 
2009-01-01  a  1  2
2009-01-02  b  3  4
2009-01-03  c  4  5 

如果在同一列中有混合的日期时间格式,你可以传递 format='mixed'

In [126]: data = StringIO("date\n12 Jan 2000\n2000-01-13\n")
In [127]: df = pd.read_csv(data)
In [128]: df['date'] = pd.to_datetime(df['date'], format='mixed')
In [129]: df
Out[129]: 
 date
0 2000-01-12
1 2000-01-13 

或者,如果你的日期时间格式都是 ISO8601(可能不完全相同格式):

In [130]: data = StringIO("date\n2020-01-01\n2020-01-01 03:00\n")
In [131]: df = pd.read_csv(data)
In [132]: df['date'] = pd.to_datetime(df['date'], format='ISO8601')
In [133]: df
Out[133]: 
 date
0 2020-01-01 00:00:00
1 2020-01-01 03:00:00 
国际日期格式

尽管美国日期格式倾向于 MM/DD/YYYY,许多国际格式使用 DD/MM/YYYY。为方便起见,提供了一个 dayfirst 关键字:

In [134]: data = "date,value,cat\n1/6/2000,5,a\n2/6/2000,10,b\n3/6/2000,15,c"
In [135]: print(data)
date,value,cat
1/6/2000,5,a
2/6/2000,10,b
3/6/2000,15,c
In [136]: with open("tmp.csv", "w") as fh:
 .....:    fh.write(data)
 .....: 
In [137]: pd.read_csv("tmp.csv", parse_dates=[0])
Out[137]: 
 date  value cat
0 2000-01-06      5   a
1 2000-02-06     10   b
2 2000-03-06     15   c
In [138]: pd.read_csv("tmp.csv", dayfirst=True, parse_dates=[0])
Out[138]: 
 date  value cat
0 2000-06-01      5   a
1 2000-06-02     10   b
2 2000-06-03     15   c 
将 CSV 写入二进制文件对象

版本 1.2.0 中的新功能。

df.to_csv(..., mode="wb") 允许将 CSV 写入以二进制模式打开的文件对象。在大多数情况下,不需要指定 mode,因为 Pandas 将自动检测文件对象是以文本模式还是二进制模式打开的。

In [139]: import io
In [140]: data = pd.DataFrame([0, 1, 2])
In [141]: buffer = io.BytesIO()
In [142]: data.to_csv(buffer, encoding="utf-8", compression="gzip") 
```### 指定浮点数转换方法
可以指定参数 `float_precision`,以在使用 C 引擎解析时使用特定的浮点数转换器。选项包括普通转换器、高���度转换器和往返转换器(在写入文件后保证往返值)。例如:
```py
In [143]: val = "0.3066101993807095471566981359501369297504425048828125"
In [144]: data = "a,b,c\n1,2,{0}".format(val)
In [145]: abs(
 .....:    pd.read_csv(
 .....:        StringIO(data),
 .....:        engine="c",
 .....:        float_precision=None,
 .....:    )["c"][0] - float(val)
 .....: )
 .....: 
Out[145]: 5.551115123125783e-17
In [146]: abs(
 .....:    pd.read_csv(
 .....:        StringIO(data),
 .....:        engine="c",
 .....:        float_precision="high",
 .....:    )["c"][0] - float(val)
 .....: )
 .....: 
Out[146]: 5.551115123125783e-17
In [147]: abs(
 .....:    pd.read_csv(StringIO(data), engine="c", float_precision="round_trip")["c"][0]
 .....:    - float(val)
 .....: )
 .....: 
Out[147]: 0.0 
```### 千位分隔符
对于使用千位分隔符编写的大数字,你可以将 `thousands` 关键字设置为长度为 1 的字符串,以便正确解析整数:
默认情况下,带有千位分隔符的数字将被解析为字符串:
```py
In [148]: data = (
 .....:    "ID|level|category\n"
 .....:    "Patient1|123,000|x\n"
 .....:    "Patient2|23,000|y\n"
 .....:    "Patient3|1,234,018|z"
 .....: )
 .....: 
In [149]: with open("tmp.csv", "w") as fh:
 .....:    fh.write(data)
 .....: 
In [150]: df = pd.read_csv("tmp.csv", sep="|")
In [151]: df
Out[151]: 
 ID      level category
0  Patient1    123,000        x
1  Patient2     23,000        y
2  Patient3  1,234,018        z
In [152]: df.level.dtype
Out[152]: dtype('O') 

thousands 关键字允许整数被正确解析:

In [153]: df = pd.read_csv("tmp.csv", sep="|", thousands=",")
In [154]: df
Out[154]: 
 ID    level category
0  Patient1   123000        x
1  Patient2    23000        y
2  Patient3  1234018        z
In [155]: df.level.dtype
Out[155]: dtype('int64') 
```### 缺失值
要控制哪些值被解析为缺失值(用 `NaN` 表示),请在 `na_values` 中指定一个字符串。如果你指定一个字符串列表,那么其中的所有值都被视为缺失值。如果你指定一个数字(一个 `float`,比如 `5.0` 或一个 `integer`,比如 `5`),则相应的等效值也将被视为缺失值(在这种情况下,实际上 `[5.0, 5]` 被识别为 `NaN`)。
要完全覆盖默认识别为缺失的值,请指定 `keep_default_na=False`。
默认识别的 `NaN` 值为 `['-1.#IND', '1.#QNAN', '1.#IND', '-1.#QNAN', '#N/A N/A', '#N/A', 'N/A', 'n/a', 'NA', '<NA>', '#NA', 'NULL', 'null', 'NaN', '-NaN', 'nan', '-nan', 'None', '']`。
让我们考虑一些例子:
```py
pd.read_csv("path_to_file.csv", na_values=[5]) 

在上面的示例中,55.0 将被识别为 NaN,除了默认值。一个字符串首先被解释为数值 5,然后作为 NaN

pd.read_csv("path_to_file.csv", keep_default_na=False, na_values=[""]) 

在上面的示例中,只有空字段将被识别为NaN

pd.read_csv("path_to_file.csv", keep_default_na=False, na_values=["NA", "0"]) 

在上面的示例中,NA0 作为字符串都被识别为 NaN

pd.read_csv("path_to_file.csv", na_values=["Nope"]) 

默认值,除了字符串"Nope",也被识别为NaN。### 无穷大

inf 类似的值将被解析为np.inf(正无穷大),而 -inf 将被解析为-np.inf(负无穷大)。这些将忽略值的大小写,意思是Inf也将被解析为np.inf。### 布尔值

常见的值TrueFalseTRUEFALSE都被识别为布尔值。偶尔你可能希望识别其他值为布尔值。要做到这一点,使用true_valuesfalse_values选项如下:

In [156]: data = "a,b,c\n1,Yes,2\n3,No,4"
In [157]: print(data)
a,b,c
1,Yes,2
3,No,4
In [158]: pd.read_csv(StringIO(data))
Out[158]: 
 a    b  c
0  1  Yes  2
1  3   No  4
In [159]: pd.read_csv(StringIO(data), true_values=["Yes"], false_values=["No"])
Out[159]: 
 a      b  c
0  1   True  2
1  3  False  4 
```### 处理“坏”行
一些文件可能有格式错误的行,字段太少或太多。字段太少的行将在尾部字段中填充 NA 值。字段太多的行将默认引发错误:
```py
In [160]: data = "a,b,c\n1,2,3\n4,5,6,7\n8,9,10"
In [161]: pd.read_csv(StringIO(data))
---------------------------------------------------------------------------
ParserError  Traceback (most recent call last)
Cell In[161], line 1
----> 1 pd.read_csv(StringIO(data))
File ~/work/pandas/pandas/pandas/io/parsers/readers.py:1026, in read_csv(filepath_or_buffer, sep, delimiter, header, names, index_col, usecols, dtype, engine, converters, true_values, false_values, skipinitialspace, skiprows, skipfooter, nrows, na_values, keep_default_na, na_filter, verbose, skip_blank_lines, parse_dates, infer_datetime_format, keep_date_col, date_parser, date_format, dayfirst, cache_dates, iterator, chunksize, compression, thousands, decimal, lineterminator, quotechar, quoting, doublequote, escapechar, comment, encoding, encoding_errors, dialect, on_bad_lines, delim_whitespace, low_memory, memory_map, float_precision, storage_options, dtype_backend)
  1013 kwds_defaults = _refine_defaults_read(
  1014     dialect,
  1015     delimiter,
   (...)
  1022     dtype_backend=dtype_backend,
  1023 )
  1024 kwds.update(kwds_defaults)
-> 1026 return _read(filepath_or_buffer, kwds)
File ~/work/pandas/pandas/pandas/io/parsers/readers.py:626, in _read(filepath_or_buffer, kwds)
  623     return parser
  625 with parser:
--> 626     return parser.read(nrows)
File ~/work/pandas/pandas/pandas/io/parsers/readers.py:1923, in TextFileReader.read(self, nrows)
  1916 nrows = validate_integer("nrows", nrows)
  1917 try:
  1918     # error: "ParserBase" has no attribute "read"
  1919     (
  1920         index,
  1921         columns,
  1922         col_dict,
-> 1923     ) = self._engine.read(  # type: ignore[attr-defined]
  1924         nrows
  1925     )
  1926 except Exception:
  1927     self.close()
File ~/work/pandas/pandas/pandas/io/parsers/c_parser_wrapper.py:234, in CParserWrapper.read(self, nrows)
  232 try:
  233     if self.low_memory:
--> 234         chunks = self._reader.read_low_memory(nrows)
  235         # destructive to chunks
  236         data = _concatenate_chunks(chunks)
File parsers.pyx:838, in pandas._libs.parsers.TextReader.read_low_memory()
File parsers.pyx:905, in pandas._libs.parsers.TextReader._read_rows()
File parsers.pyx:874, in pandas._libs.parsers.TextReader._tokenize_rows()
File parsers.pyx:891, in pandas._libs.parsers.TextReader._check_tokenize_status()
File parsers.pyx:2061, in pandas._libs.parsers.raise_parser_error()
ParserError: Error tokenizing data. C error: Expected 3 fields in line 3, saw 4 

你可以选择跳过坏行:

In [162]: data = "a,b,c\n1,2,3\n4,5,6,7\n8,9,10"
In [163]: pd.read_csv(StringIO(data), on_bad_lines="skip")
Out[163]: 
 a  b   c
0  1  2   3
1  8  9  10 

在版本 1.4.0 中新增。

或者通过传递一个可调用函数来处理engine="python"时的错误行。错误行将是由sep分割的字符串列表:

In [164]: external_list = []
In [165]: def bad_lines_func(line):
 .....:    external_list.append(line)
 .....:    return line[-3:]
 .....: 
In [166]: external_list
Out[166]: [] 

注意

可调用函数只会处理字段过多的行。其他错误导致的坏行将被默默跳过。

In [167]: bad_lines_func = lambda line: print(line)
In [168]: data = 'name,type\nname a,a is of type a\nname b,"b\" is of type b"'
In [169]: data
Out[169]: 'name,type\nname a,a is of type a\nname b,"b" is of type b"'
In [170]: pd.read_csv(StringIO(data), on_bad_lines=bad_lines_func, engine="python")
Out[170]: 
 name            type
0  name a  a is of type a 

在这种情况下,该行未被处理,因为这里的“坏行”是由转义字符引起的。

你还可以使用usecols参数来消除一些行中出现但其他行中没有的多余列数据:

In [171]: pd.read_csv(StringIO(data), usecols=[0, 1, 2])
---------------------------------------------------------------------------
ValueError  Traceback (most recent call last)
Cell In[171], line 1
----> 1 pd.read_csv(StringIO(data), usecols=[0, 1, 2])
File ~/work/pandas/pandas/pandas/io/parsers/readers.py:1026, in read_csv(filepath_or_buffer, sep, delimiter, header, names, index_col, usecols, dtype, engine, converters, true_values, false_values, skipinitialspace, skiprows, skipfooter, nrows, na_values, keep_default_na, na_filter, verbose, skip_blank_lines, parse_dates, infer_datetime_format, keep_date_col, date_parser, date_format, dayfirst, cache_dates, iterator, chunksize, compression, thousands, decimal, lineterminator, quotechar, quoting, doublequote, escapechar, comment, encoding, encoding_errors, dialect, on_bad_lines, delim_whitespace, low_memory, memory_map, float_precision, storage_options, dtype_backend)
  1013 kwds_defaults = _refine_defaults_read(
  1014     dialect,
  1015     delimiter,
   (...)
  1022     dtype_backend=dtype_backend,
  1023 )
  1024 kwds.update(kwds_defaults)
-> 1026 return _read(filepath_or_buffer, kwds)
File ~/work/pandas/pandas/pandas/io/parsers/readers.py:620, in _read(filepath_or_buffer, kwds)
  617 _validate_names(kwds.get("names", None))
  619 # Create the parser.
--> 620 parser = TextFileReader(filepath_or_buffer, **kwds)
  622 if chunksize or iterator:
  623     return parser
File ~/work/pandas/pandas/pandas/io/parsers/readers.py:1620, in TextFileReader.__init__(self, f, engine, **kwds)
  1617     self.options["has_index_names"] = kwds["has_index_names"]
  1619 self.handles: IOHandles | None = None
-> 1620 self._engine = self._make_engine(f, self.engine)
File ~/work/pandas/pandas/pandas/io/parsers/readers.py:1898, in TextFileReader._make_engine(self, f, engine)
  1895     raise ValueError(msg)
  1897 try:
-> 1898     return mappingengine
  1899 except Exception:
  1900     if self.handles is not None:
File ~/work/pandas/pandas/pandas/io/parsers/c_parser_wrapper.py:155, in CParserWrapper.__init__(self, src, **kwds)
  152     # error: Cannot determine type of 'names'
  153     if len(self.names) < len(usecols):  # type: ignore[has-type]
  154         # error: Cannot determine type of 'names'
--> 155         self._validate_usecols_names(
  156             usecols,
  157             self.names,  # type: ignore[has-type]
  158         )
  160 # error: Cannot determine type of 'names'
  161 self._validate_parse_dates_presence(self.names)  # type: ignore[has-type]
File ~/work/pandas/pandas/pandas/io/parsers/base_parser.py:979, in ParserBase._validate_usecols_names(self, usecols, names)
  977 missing = [c for c in usecols if c not in names]
  978 if len(missing) > 0:
--> 979     raise ValueError(
  980         f"Usecols do not match columns, columns expected but not found: "
  981         f"{missing}"
  982     )
  984 return usecols
ValueError: Usecols do not match columns, columns expected but not found: [0, 1, 2] 

如果你想保留所有数据,包括字段过多的行,你可以指定足够数量的names。这样可以确保字段不足的行填充为NaN

In [172]: pd.read_csv(StringIO(data), names=['a', 'b', 'c', 'd'])
Out[172]: 
 a                b   c   d
0    name             type NaN NaN
1  name a   a is of type a NaN NaN
2  name b  b is of type b" NaN NaN 
```### 方言
`dialect`关键字提供了更大的灵活性,用于指定文件格式。默认情况下,它使用 Excel 方言,但你可以指定方言名称或[`csv.Dialect`](https://docs.python.org/3/library/csv.html#csv.Dialect "(在 Python v3.12)")实例。
假设你有一些未封闭引号的数据:
```py
In [173]: data = "label1,label2,label3\n" 'index1,"a,c,e\n' "index2,b,d,f"
In [174]: print(data)
label1,label2,label3
index1,"a,c,e
index2,b,d,f 

默认情况下,read_csv使用 Excel 方言,并将双引号视为引号字符,这会导致在找到关闭双引号之前找到换行符时失败。

我们可以通过使用dialect来避免这种情况:

In [175]: import csv
In [176]: dia = csv.excel()
In [177]: dia.quoting = csv.QUOTE_NONE
In [178]: pd.read_csv(StringIO(data), dialect=dia)
Out[178]: 
 label1 label2 label3
index1     "a      c      e
index2      b      d      f 

所有的方言选项都可以通过关键字参数单独指定:

In [179]: data = "a,b,c~1,2,3~4,5,6"
In [180]: pd.read_csv(StringIO(data), lineterminator="~")
Out[180]: 
 a  b  c
0  1  2  3
1  4  5  6 

另一个常见的方言选项是skipinitialspace,用于跳过分隔符后的任何空白:

In [181]: data = "a, b, c\n1, 2, 3\n4, 5, 6"
In [182]: print(data)
a, b, c
1, 2, 3
4, 5, 6
In [183]: pd.read_csv(StringIO(data), skipinitialspace=True)
Out[183]: 
 a  b  c
0  1  2  3
1  4  5  6 

解析器会尽力“做正确的事情”,并且不易受损。类型推断是一件很重要的事情。如果一个列可以被强制转换为整数类型而不改变内容,解析器将这样做。任何非数字列将与其他 pandas 对象一样以对象 dtype 传递。### 引用和转义字符

嵌套字段中的引号(和其他转义字符)可以以多种方式处理。一种方法是使用反斜杠;为了正确解析这些数据,你应该传递escapechar选项:

In [184]: data = 'a,b\n"hello, \\"Bob\\", nice to see you",5'
In [185]: print(data)
a,b
"hello, \"Bob\", nice to see you",5
In [186]: pd.read_csv(StringIO(data), escapechar="\\")
Out[186]: 
 a  b
0  hello, "Bob", nice to see you  5 
```### 固定宽度列的文件
当 `read_csv()` 读取分隔数据时,`read_fwf()` 函数与具有已知和固定列宽的数据文件一起工作。`read_fwf` 的函数参数与 `read_csv` 大致相同,但有两个额外参数,并且 `delimiter` 参数的用法不同:
+   `colspecs`:一个给出每行固定宽度字段范围的对(元组)列表,作为半开区间(即,[from, to[)。字符串值 ‘infer’ 可以用于指示解析器尝试从数据的前 100 行检测列规格。如果未指定,默认行为是推断。
+   `widths`:一个字段宽度列表,可以代替 ‘colspecs’ 使用,如果间隔是连续的。
+   `delimiter`:固定宽度文件中要考虑为填充字符的字符。如果字段的填充字符不是空格(例如,‘~’),可以使用它来指定填充字符。
考虑一个典型的固定宽度数据文件:
```py
In [187]: data1 = (
 .....:    "id8141    360.242940   149.910199   11950.7\n"
 .....:    "id1594    444.953632   166.985655   11788.4\n"
 .....:    "id1849    364.136849   183.628767   11806.2\n"
 .....:    "id1230    413.836124   184.375703   11916.8\n"
 .....:    "id1948    502.953953   173.237159   12468.3"
 .....: )
 .....: 
In [188]: with open("bar.csv", "w") as f:
 .....:    f.write(data1)
 .....: 

为了将此文件解析为 DataFrame,我们只需向 read_fwf 函数提供列规范和文件名即可:

# Column specifications are a list of half-intervals
In [189]: colspecs = [(0, 6), (8, 20), (21, 33), (34, 43)]
In [190]: df = pd.read_fwf("bar.csv", colspecs=colspecs, header=None, index_col=0)
In [191]: df
Out[191]: 
 1           2        3
0 
id8141  360.242940  149.910199  11950.7
id1594  444.953632  166.985655  11788.4
id1849  364.136849  183.628767  11806.2
id1230  413.836124  184.375703  11916.8
id1948  502.953953  173.237159  12468.3 

请注意,当指定了 header=None 参数时,解析器会自动选择列名 X.。或者,您可以只为连续的列提供列宽度:

# Widths are a list of integers
In [192]: widths = [6, 14, 13, 10]
In [193]: df = pd.read_fwf("bar.csv", widths=widths, header=None)
In [194]: df
Out[194]: 
 0           1           2        3
0  id8141  360.242940  149.910199  11950.7
1  id1594  444.953632  166.985655  11788.4
2  id1849  364.136849  183.628767  11806.2
3  id1230  413.836124  184.375703  11916.8
4  id1948  502.953953  173.237159  12468.3 

解析器将处理围绕列周围的额外空白,因此在文件中列之间有额外分隔是可以的。

默认情况下,read_fwf 将尝试通过使用文件的前 100 行推断文件的 colspecs。它只能在列对齐并且由提供的 delimiter(默认分隔符是空白符)正确分隔的情况下执行此操作。

In [195]: df = pd.read_fwf("bar.csv", header=None, index_col=0)
In [196]: df
Out[196]: 
 1           2        3
0 
id8141  360.242940  149.910199  11950.7
id1594  444.953632  166.985655  11788.4
id1849  364.136849  183.628767  11806.2
id1230  413.836124  184.375703  11916.8
id1948  502.953953  173.237159  12468.3 

read_fwf 支持 dtype 参数,用于指定解析列的类型与推断类型不同。

In [197]: pd.read_fwf("bar.csv", header=None, index_col=0).dtypes
Out[197]: 
1    float64
2    float64
3    float64
dtype: object
In [198]: pd.read_fwf("bar.csv", header=None, dtype={2: "object"}).dtypes
Out[198]: 
0     object
1    float64
2     object
3    float64
dtype: object 


Pandas 2.2 中文官方教程和指南(十·一)(2)https://developer.aliyun.com/article/1509772

相关文章
|
SQL 数据采集 数据挖掘
Pandas 教程
10月更文挑战第25天
271 2
|
数据采集 存储 数据可视化
Pandas高级教程:数据清洗、转换与分析
Pandas是Python的数据分析库,提供Series和DataFrame数据结构及数据分析工具,便于数据清洗、转换和分析。本教程涵盖Pandas在数据清洗(如缺失值、重复值和异常值处理)、转换(数据类型转换和重塑)和分析(如描述性统计、分组聚合和可视化)的应用。通过学习Pandas,用户能更高效地处理和理解数据,为数据分析任务打下基础。
1459 3
|
存储 JSON 数据格式
Pandas 使用教程 CSV - CSV 转 JSON
Pandas 使用教程 CSV - CSV 转 JSON
171 0
|
JSON 数据格式 Python
Pandas 使用教程 JSON
Pandas 使用教程 JSON
223 0
|
SQL 数据采集 JSON
Pandas 使用教程 Series、DataFrame
Pandas 使用教程 Series、DataFrame
320 0
|
索引 Python
Pandas 2.2 中文官方教程和指南(一)(4)
Pandas 2.2 中文官方教程和指南(一)
201 0
|
存储 SQL JSON
Pandas 2.2 中文官方教程和指南(一)(3)
Pandas 2.2 中文官方教程和指南(一)
253 0
|
XML 关系型数据库 PostgreSQL
Pandas 2.2 中文官方教程和指南(一)(2)
Pandas 2.2 中文官方教程和指南(一)
525 0
|
XML 关系型数据库 MySQL
Pandas 2.2 中文官方教程和指南(一)(1)
Pandas 2.2 中文官方教程和指南(一)
880 0
|
C++ 索引 Python
Pandas 2.2 中文官方教程和指南(五)(4)
Pandas 2.2 中文官方教程和指南(五)
140 0