课程
pandas 是一款广泛用于数据科学、数据分析与机器学习的 Python 库。它为处理各种规模的数据集提供了灵活直观的方式。pandas 最重要的功能之一,就是其提供的读写数据的工具。
对于以表格形式存储在 CSV 文件中的数据,您可以使用 pandas 的 read_csv() 函数将其读入内存,并返回一个 pandas 数据框。
本文将带您全面了解 read_csv() 函数,以及如何通过调整参数自定义输出。我们也会介绍如何将 pandas 数据框写出为 CSV 文件。
注意:请查看这份DataLab 工作簿,跟随代码一起练习。
使用 read_csv() 函数导入 CSV 文件
在将 CSV 文件读入 pandas 数据框(dataframe)之前,您应先对数据内容有一些了解。因此,建议您在尝试将其加载到内存之前先快速浏览文件:这将帮助您更好地判断哪些列是必要的、哪些可以丢弃。
现在,让我们编写一些代码,使用 read_csv() 导入文件。随后,我们再讨论其中发生了什么,以及在将数据读入内存时如何自定义输出。
# Tip: For faster performance on large files in pandas 2.0+, use the pyarrow engine
# airbnb_data = pd.read_csv("data/listings_austin.csv", engine="pyarrow")
import pandas as pd
# Read the CSV file
airbnb_data = pd.read_csv("data/listings_austin.csv")
# View the first 5 rows
airbnb_data.head()

上述代码所做的事情是:
- 在环境中导入 pandas 库
- 将文件路径传给
read_csv(),把数据读入内存为一个 pandas 数据框。 - 打印该数据框的前五行。
不过,read_csv() 函数还能做的远不止这些。
将某列设为索引
pandas 的默认行为是为从 CSV 加载到内存的数据框添加一个起始索引。不过,您可以通过设置 index_col 参数,在 read_csv() 函数中明确指定将哪一列作为索引。
请注意,赋予 index_col 的值可以是列名字符串、列索引,或由列名/列索引构成的序列。将该参数设为序列将得到一个多级索引(multiIndex,即按多个层级对数据进行分组)。
我们再次读取数据,并将 id 列设为索引。
# Setting the id column as the index
airbnb_data = pd.read_csv("data/listings_austin.csv", index_col="id")
# airbnb_data = pd.read_csv("data/listings_austin.csv", index_col=0)
# Preview first 5 rows
airbnb_data.head()
选择特定列读入内存
如果您只想将特定列读入内存,因为并非所有列都重要,怎么办?这在现实世界中很常见。使用 read_csv() 函数,您可以在加载文件后只选择所需列,但如果希望在 read_csv() 函数内部完成该操作,前提是您事先就知道需要哪些列。
如果您确实知道所需列,那就太好了;可以将一个类列表对象传递给 read_csv() 的 usecols 参数,从而节省时间和内存。
# Defining the columns to read
usecols = ["id", "name", "host_id", "neighbourhood", "room_type", "price", "minimum_nights"]
# Read data with subset of columns
airbnb_data = pd.read_csv("data/listings_austin.csv", index_col="id", usecols=usecols)
# Preview first 5 rows
airbnb_data.head()
我们仅仅触及了自定义 read_csv() 输出的皮毛,若再深入就会信息过载。您可以参考下表:
常用 read_csv() 参数
| Parameter | Description | Example usage | |
|---|---|---|---|
| filepath_or_buffer | 要读取的 CSV 文件路径或 URL。 | pd.read_csv("data/listings_austin.csv") | |
| sep | 使用的分隔符。默认是 , 。 | pd.read_csv("data.csv", sep=';') | |
| index_col | 要设为索引的列(可为列标签或整数)。 | pd.read_csv("data.csv", index_col="id") | |
| usecols | 仅返回列的子集。接受列名或索引的类列表对象。 | pd.read_csv("data.csv", usecols=["id", "name", "price"]) | |
| names | 使用的列名列表。若文件不包含表头行时使用。 | pd.read_csv("data.csv", names=["A", "B", "C"]) | |
| header | 用作列名的行号。默认是 0(第一行)。 | pd.read_csv("data.csv", header=1) | |
| dtype | 数据或列的数据类型。 | pd.read_csv("data.csv", dtype={"id": int, "price": float}) | |
| na_values | 识别为 NA/NaN 的其他字符串。 | pd.read_csv("data.csv", na_values=["NA", "N/A"]) | |
| parse_dates | 尝试解析日期。可为布尔值或列名列表。 | pd.read_csv("data.csv", parse_dates=["date"]) | |
| engine | 解析引擎:'c'(默认)、'python',或 'pyarrow'(最快,需安装 pyarrow)。 | pd.read_csv("data.csv", engine="pyarrow") | |
| skiprows | 要跳过的行号(从 0 开始)或开头要跳过的行数。 | pd.read_csv("data.csv", skiprows=3) | |
| nrows | 要读取的行数。用于预览大型文件。 | pd.read_csv("data.csv", nrows=100) |
使用 chunksize 处理大型数据集
处理大型数据集时,可能无法一次性将整个文件加载到内存,尤其在内存受限的环境中。read_csv() 提供了一个实用的 chunksize 参数,让您以更小且可管理的块来读取数据。
设置 chunksize 后,read_csv() 会返回一个可迭代对象,每次迭代都会提供一个以 pandas 数据框表示的数据块。这种方式在分批处理数据或当数据集大小超出可用内存时尤其有用。
以下是 chunksize 参数的用法示例:
import pandas as pd
import os # Import the standard OS library
file_path = "data/large_dataset.csv"
output_file = "data/processed_large_dataset.csv"
chunk_size = 10000
# Process and write chunks
for chunk in pd.read_csv(file_path, chunksize=chunk_size):
# Example: Filter rows based on a condition
filtered_chunk = chunk[chunk['column_name'] > 50]
# Check if header is needed (only if file doesn't exist yet)
write_header = not os.path.exists(output_file)
# Append to a new CSV file
filtered_chunk.to_csv(output_file, mode='a', header=write_header, index=False)如果您的目标是在整个数据集上执行某个操作,例如计算某列的总和,您可以在遍历各个块的同时进行聚合:
total_sum = 0
for chunk in pd.read_csv(file_path, chunksize=chunk_size):
# Add the sum of the specific column for each chunk
total_sum += chunk['column_name'].sum()
print(f"Total sum of the column: {total_sum}")您还可以使用 chunksize 逐步处理并将数据块保存到新文件中:
# Output file path
output_file = "data/processed_large_dataset.csv"
# Process and write chunks
for chunk in pd.read_csv(file_path, chunksize=chunk_size):
# Example: Filter rows based on a condition
filtered_chunk = chunk[chunk['column_name'] > 50]
# Append to a new CSV file
filtered_chunk.to_csv(output_file, mode='a', header=not os.path.exists(output_file), index=False)我们会在后续章节中进一步看到 to_csv() 方法。
在以下情况下,chunksize 参数不可或缺:
- 处理大于可用内存的数据集。
- 分阶段进行数据清洗或转换。
- 渐进式分析或处理大型文件。
从 URL 读取数据
一旦掌握了如何从本地存储将 CSV 文件读入内存,从其他来源读取数据就轻而易举了。本质上过程相同,只是不再传入文件路径。
假设某个网页上有您需要的数据;该如何将其读入内存?
这里以UCI 仓库的 Iris 数据集为例:
# Webpage URL
url = "https://archive.ics.uci.edu/ml/machine-learning-databases/iris/iris.data"
# Define the column names
col_names = ["sepal_length_in_cm",
"sepal_width_in_cm",
"petal_length_in_cm",
"petal_width_in_cm",
"class"]
# Read data from URL
iris_data = pd.read_csv(url, names=col_names)
iris_data.head() 
搞定!
我们将一个字符串列表赋给了 names 参数。由于原始的 Iris 数据没有表头行,该参数告诉 pandas 使用我们的列表作为列名。(注意:如果文件有表头行,您还需要使用 header=0 告诉 pandas 用它来替换。)
DataFrame 结构的方法与属性
pandas 库中最常见的对象就是数据框(dataframe)。它是一种二维带标签的数据结构,由行和列组成,各列可具有不同的数据类型(如浮点、数值、分类型等)。
从概念上讲,您可以将 pandas 数据框看作电子表格、SQL 表,或由若干 series 对象构成的字典——选您最熟悉的理解方式。pandas 数据框的妙处在于,它自带许多方法,能让您尽快熟悉数据。
您已经见过其中一个方法:iris_data.head(),它会显示前 n 行(默认 5 行)。与 head() 相“对应”的方法是 tail(),它会显示该数据框对象最后的 n 行(默认 5 行)。例如:
iris_data.tail()
您可以通过数据框对象的 columns 属性快速查看列名:
# Discover the column names
iris_data.columns
"""
Index(['sepal_length_in_cm', 'sepal_width_in_cm', 'petal_length_in_cm',
'petal_width_in_cm', 'class'],
dtype='object')
"""另一个重要方法是 info()。它会打印出数据框的简明摘要,包括索引、数据类型、列、非空值以及内存使用情况。
# Get summary information of the dataframe
iris_data.info()
"""
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 150 entries, 0 to 149
Data columns (total 5 columns):
# Column Non-Null Count Dtype
--- ------ -------------- -----
0 sepal_length_in_cm 150 non-null float64
1 sepal_width_in_cm 150 non-null float64
2 petal_length_in_cm 150 non-null float64
3 petal_width_in_cm 150 non-null float64
4 class 150 non-null object
dtypes: float64(4), object(1)
memory usage: 6.0+ KB
"""DataFrame.describe() 会生成描述性统计信息,包括用于概括数据集分布的集中趋势、离散程度和形状的统计量。若数据存在缺失值,不用担心;描述性统计会排除它们。
让我们对 Iris 数据集调用 describe 方法:
# Get descriptive statistics
iris_data.describe()
将 DataFrame 导出到 CSV 文件
pandas 数据框还提供了 to_csv() 方法。当您完成清洗与预处理后,下一步可能是将数据框导出为文件——这非常简单:
# Export the file to the current working directory
iris_data.to_csv("cleaned_iris_data.csv")执行这段代码会在当前工作目录下创建一个名为 cleaned_iris_data.csv 的 CSV 文件。
但如果您想使用不同的分隔符来标记数据单元的开始和结束,或者想指定缺失值的表示方式呢?也许您不希望将表头导出到文件中。
没问题,您可以根据要求调整 to_csv() 方法的参数,以满足导出数据的需要。
我们来看几个调整 to_csv() 输出的示例:
- 导出到当前工作目录,但使用制表符作为分隔符:
# Change the delimiter to a tab
iris_data.to_csv("tab_separated_iris_data.csv", sep="\t")- 不包含索引地导出数据:
# Export data without the index
iris_data.to_csv("tab_separated_iris_data.csv", sep="\t", index=False)
# If you get UnicodeEncodeError use this...
# iris_data.to_csv("tab_separated_iris_data.csv", sep="\t", index=False, encoding='utf-8')- 更改缺失值的表示(默认是
““):
# Replace missing values with "Unknown"
iris_data.to_csv("tab_separated_iris_data.csv", sep="\t", na_rep="Unknown")- 导出不带表头(列名)的数据框到文件:
# Do not include headers when exporting the data
iris_data.to_csv("tab_separated_iris_data.csv", sep="\t", na_rep="Unknown", header=False)处理编码问题
有时您可能会遇到编码错误,尤其是在系统默认编码不是 UTF-8,或数据包含非 ASCII 字符时。为解决这些问题,您可以通过 encoding 参数指定合适的编码。
# Export data with a specified encoding
iris_data.to_csv("cleaned_iris_data.csv", encoding="utf-8")
如果您的系统使用不同的编码(例如 Windows 常见的 Windows-1252),可以显式指定:
# Export data using a different encoding
iris_data.to_csv("cleaned_iris_data.csv", encoding="cp1252")
带有更多参数的示例:
# Handle missing values and encoding issues
iris_data.to_csv("cleaned_iris_data.csv", na_rep="Unknown", encoding="utf-8", index=False)上述示例可确保导出的 CSV 文件与多种系统和应用程序兼容。
常用 to_csv() 参数
| Parameter | Description | Example usage |
|---|---|---|
| path_or_buf | 文件路径或对象;若为 None,则返回字符串。 | df.to_csv("output.csv") |
| sep | 长度为 1 的字符串。输出文件的字段分隔符。默认为 ','. | df.to_csv("output.csv", sep=';') |
| na_rep | 缺失数据的表示。 | df.to_csv("output.csv", na_rep='Unknown') |
| float_format | 浮点数的格式化字符串。 | df.to_csv("output.csv", float_format='%.2f') |
| columns | 要写出的列。默认写出所有列。 | df.to_csv("output.csv", columns=["id", "name"]) |
| header | 是否写出列名。若提供字符串列表,则视为列名的别名。 | df.to_csv("output.csv", header=False) |
| index | 是否写出行名(索引)。默认 True。 | df.to_csv("output.csv", index=False) |
| mode | Python 写入模式。默认 'w'。 | df.to_csv("output.csv", mode='a') |
| encoding | 输出文件使用的编码。 | df.to_csv("output.csv", encoding='utf-8') |
处理 CSV 的替代 Python 库
尽管 pandas 是处理 CSV 文件功能强大且通用的库,但它并非唯一选择。根据您的使用场景,其他库可能更适合特定任务:
csv 模块(标准库)
csv 模块是 Python 标准库的一部分,是处理 CSV 的轻量级替代方案。它提供读取和写入 CSV 的基础功能,无需额外安装。csv 的优点包括:
- 无需外部依赖。
- 轻量且适合简单的 CSV 任务。
- 对读写操作有更细粒度的控制。
示例:
import csv
# Reading a CSV file
with open("data/sample.csv", mode="r") as file:
reader = csv.reader(file)
for row in reader:
print(row)
# Writing to a CSV file
with open("data/output.csv", mode="w", newline="") as file:
writer = csv.writer(file)
writer.writerow(["Column1", "Column2"])
writer.writerow(["Value1", "Value2"])NumPy
NumPy 是用于 Python 数值计算的库,也支持 CSV 处理。在处理数值数据或对性能有要求时尤其有用。其优点包括:
- 对数值数据具有高性能。
- 与基于数组的工作流集成良好。
- 高效处理大型数据集。
示例:
import numpy as np
# Reading a CSV file into a NumPy array
data = np.loadtxt("data/sample.csv", delimiter=",", skiprows=1)
# Writing a NumPy array to a CSV file
np.savetxt("data/output.csv", data, delimiter=",")虽然 NumPy 高效,但它不具备 pandas 所提供的丰富数据处理与探索功能。
Polars
如果您在处理超大数据集时觉得 pandas 速度慢或内存不足,Polars 是值得了解的现代接班人。它是用 Rust 编写的数据框库,专为极致性能和并行处理而设计。
正如我们在Polars 教程中所探讨的,Polars 的优势包括:
- 速度:它是多线程的,能利用全部 CPU 内核,比 pandas 更快地读写数据。
- 内存效率:它的内存管理更高效,常常能在同一台机器上处理更大的数据集。
- 惰性求值:它可以在运行前优化查询,在复杂操作中节省时间。
示例:其语法与 pandas 往往相当相似,易于上手:
import polars as pl
# Read a CSV file (automatically uses multiple threads)
df = pl.read_csv("data/large_dataset.csv")
# View the first 5 rows
print(df.head())
# Write to a CSV file
df.write_csv("data/polars_output.csv")总结
让我们回顾一下本教程的内容;您已经学会了如何:
- 使用 pandas 库的
read_csv()函数导入 CSV 文件。 - 在将数据读入内存时设置列索引。
- 指定希望
read_csv()返回的数据列。 - 使用
pandas.read_csv()从 URL 读取数据。 - 利用数据框对象的方法与属性快速获取数据洞察。
- 将数据框对象导出为 CSV 文件。
- 通过
to_csv()方法自定义导出文件的输出。
在本教程中,我只从 CSV 文件的角度专注于数据的导入与导出;现在,您已经对使用 pandas 导入与导出 CSV 文件的实用性有了清晰认识。CSV 是最常见的数据存储格式之一,但并非唯一。数据科学中还使用多种其他文件格式,例如parquet、JSON 和 Excel。
网上托管了大量有用且高质量的数据集,您可以通过 API 等方式访问。如果您想更深入地了解如何在 Python 中加载数据,DataCamp 的 Introduction to Importing Data in Python 课程会教授所有最佳实践。
我们还有如何将 JSON 和 HTML 数据导入 pandas 的教程,以及一份面向初学者的 pandas 终极指南。务必去看看,深入了解 pandas 框架。
FAQs
pandas 能读取使用不同分隔符(如分号或制表符)的 CSV 文件吗?
可以。pandas 可通过 sep 参数读取使用不同分隔符的 CSV 文件。例如,对分号分隔的文件,可使用 pd.read_csv('file.csv', sep=';')。
读取文件时,如何处理 CSV 文件中的缺失值?
您可以在 read_csv() 函数中使用 na_values 参数,指定需要识别为 NA/NaN 的其他字符串。例如,pd.read_csv('file.csv', na_values=['NA', 'missing'])。
如何高效地用 pandas 读取大型 CSV 文件?
对于大型 CSV 文件,建议使用 chunksize 参数以分块读取。这样按段读取数据,更加节省内存。例如,pd.read_csv('file.csv', chunksize=1000)。
使用 pandas 读取 CSV 时,能否跳过某些行?
可以。您可以在 read_csv() 中使用 skiprows 参数来跳过行。您可以指定要跳过的行数,或给出要跳过的行索引列表。
读取 CSV 时,如何确保为某列指定特定数据类型?
使用 dtype 参数为列指定数据类型。例如,pd.read_csv('file.csv', dtype={'column_name': 'int32'})。
使用 pandas 读取 CSV 时,可以解析日期吗?
可以。您可以使用 parse_dates 参数来解析日期。您可以指定哪些列应解析为日期,例如 pd.read_csv('file.csv', parse_dates=['date_column'])。
如果我的 CSV 文件包含注释,导入时如何忽略?
使用 comment 参数指定注释起始字符。以该字符开头的行会被跳过。例如,pd.read_csv('file.csv', comment='#')。
如何处理包含多行表头的 CSV 文件?
使用 header 参数指定哪一行作为列名。若存在多行表头,也可以使用 names 参数来指定新的列名。
如果一个 CSV 文件包含多张表,如何用 pandas 读取其中的特定表?
如果文件结构较为复杂,可能需要先进行预处理,或借助其他库来提取特定表格。仅靠 pandas 可能无法直接处理复杂的多表 CSV 文件。
使用 pandas 读取 CSV 时如何处理编码问题?
使用 encoding 参数指定文件编码。例如,若遇到编码错误,可尝试 pd.read_csv('file.csv', encoding='utf-8') 或 pd.read_csv('file.csv', encoding='latin1')。