大多数时候,我们要处理分析的数据是存储在不同格式的文件中的,有txt、csv、excel、json、xml以及二进制等磁盘文件格式,还有时候是从数据库以及从Web API中交互获取要处理的数据。现在开始学习如何用pandas从以上内容中输入和输出数据。
读取和写入文本格式数据
pandas具有许多函数,用于将表格数据作为DataFrame对象读取。下面列表列出来一些常用的函数,pandas.read_csv 是最常用的方法之一。这一次主要学习从各种格式的文本文件中存取数据,后面还要学习从二进制数据格式文件中存取数据。
以下列表:pandas 中的文本和二进制数据加载函数
函数 | 描述 |
read_csv | 从文件、URL 或类似文件的对象加载分隔数据;使用逗号作为默认分隔符 |
read_fwf | 以固定宽度的列格式读取数据(即无分隔符) |
read_clipboard | 从剪贴板读取数据的read_csv函数的变体;用于从网页转换表格 |
read_excel | 从 Excel XLS 或 XLSX 文件中读取表格数据 |
read_hdf | 读取 pandas 写入的 HDF5 文件 |
read_html | 读取给定 HTML 文档中找到的所有表格数据 |
read_json | 从 JSON 字符串表示形式、文件、URL 或类似文件的对象中读取数据 |
read_feather | 读取 Feather 二进制文件格式 |
read_orc | 读取 Apache ORC 二进制文件格式 |
read_parquet | 读取 Apache Parquet 二进制文件格式 |
read_pickle | 读取 pandas 存储的Python pickle 格式对象 |
read_sas | 读取SAS 数据集;由 SAS 系统的自定义存储格式之一存储 |
read_spss | 读取 SPSS 创建的数据文件 |
read_sql | 读取 SQL 查询的结果(使用 SQLAlchemy) |
read_sql_table | 读取整个 SQL 表(使用 SQLAlchemy);等效于使用 read_sql 选择该表中所有内容的查询 |
read_stata | 从 Stata 文件格式读取数据集 |
read_xml | 从 XML 文件中读取数据表 |
这些函数旨在将文本数据转换为 DataFrame,我们先大概了解下这些函数的作用机制。这些函数的可选参数可能分为几类:
Indexing(索引):
可以将一个或多个列视为返回的 DataFrame,以及是否从文件中获取列名等。
Type inference and data conversion(类型推断和数据转换):
包括用户自定义的值转换和缺失值标记的自定义列表等。
Date and time parsing(日期和时间解析)
包括组合功能,可以将分布在多个列中的日期和时间信息合并到结果中的单个列中。
Iterating(迭代):
支持迭代非常大的文件(块)。
Unclean data issues(脏数据问题):
跳过行数据,如页脚、注释或类似于用逗号分隔的千位数字数据的其他小内容数据。
由于现实世界中的数据可能非常混乱,因此随着时间的推移,为了处理这些数据,一些数据加载函数(尤其是 pandas.read_csv)已经积累了一长串可选参数。一开始对这些参数不知所措是正常的(pandas.read_csv 大约有 50 个)。在线 pandas 官方文档有许多关于这些参数工作原理的示例,我们可以找到一个足够相似的示例来帮助我们正确的使用参数。
因为有些文件的 column 数据类型不是数据格式的一部分,所以一些函数提供了类型推理功能。这意味着我们不必指定哪些列是数字、整数、布尔值或字符串。另外有一些数据格式(如 HDF5、ORC 和 Parquet)在格式中嵌入了数据类型信息。
对于处理日期和其他自定义类型,我们可能需要应用更多的其他一些处理方法。
下面我将从读取处理一个小的逗号分隔值 的(CSV) 文本文件开始学习,这个文件名是ex1.csv,存储在examples目录中,examples目录与处理它的Python pandas代码存储在相同目录下,ex1.csv的数据内容如下,另外再创建一个ex2.csv文件,这个文件的数据内容跟ex1.csv一样,只是没有标题行。
通过pandas.read_csv函数将其读取出来,并打印到vs code控制台(很简单,不要搞错文件的存储目录和文件名)
import numpy as np
import pandas as pddf = pd.read_csv("examples/ex1.csv")
print(df)
jupyter中输出的pandas对象:
a | b | c | d | message | |
---|---|---|---|---|---|
0 | 1 | 2 | 3 | 4 | hello |
1 | 5 | 6 | 7 | 8 | world |
2 | 9 | 10 | 11 | 12 | foo |
对于没有标题行的文件ex2.csv,读取此文件,可以允许 pandas 分配默认列名称,也可以自己指定名称,如下代码。
import numpy as np
import pandas as pd#pandas默认制定列名
a = pd.read_csv("examples/ex2.csv", header=None)#用names指定列名。
b = pd.read_csv("examples/ex2.csv", names=["a", "b", "c", "d", "message"])#指定 message 列成为返回的 DataFrame 的索引。
#可以指定索引位于第4列,也可以使用 index_col 参数将其命名为 “message”
names = ["a", "b", "c", "d", "message"]
c = pd.read_csv("examples/ex2.csv", names=names, index_col="message")
设置header=None,则read_csv输出(默认分配列名0 1 2 3 4):
0 | 1 | 2 | 3 | 4 | |
---|---|---|---|---|---|
0 | 1 | 2 | 3 | 4 | hello |
1 | 5 | 6 | 7 | 8 | world |
2 | 9 | 10 | 11 | 12 | foo |
用names指定列名输出:
a | b | c | d | message | |
---|---|---|---|---|---|
0 | 1 | 2 | 3 | 4 | hello |
1 | 5 | 6 | 7 | 8 | world |
2 | 9 | 10 | 11 | 12 | foo |
用names指定列名,同时用index_col指定message为列索引名,输出:
a | b | c | d | |
---|---|---|---|---|
message | ||||
hello | 1 | 2 | 3 | 4 |
world | 5 | 6 | 7 | 8 |
foo | 9 | 10 | 11 | 12 |
如果我们想要从多个列中形成分层索引(后面的学习中还会深入学习分层索引),可以传递列号或名称列表。我们创建一个csv_mindex.csv文件,其内容如下图
我们用read_csv读取该文件,并用index_col指定列名称形成分层索引:
import numpy as np
import pandas as pdparsed = pd.read_csv("examples/csv_mindex.csv", index_col=["key1", "key2"])
print(parsed)
输出结果如下:
value1 | value2 | ||
---|---|---|---|
key1 | key2 | ||
one | a | 1 | 2 |
b | 3 | 4 | |
c | 5 | 6 | |
d | 7 | 8 | |
two | a | 9 | 10 |
b | 11 | 12 | |
c | 13 | 14 | |
d | 15 | 16 |
在某些情况下,表格中可能没有固定的分隔符,会使用空格或其他模式来分隔字段。我们来看文本文件ex3.txt中的内容(空格分隔字典),如下图:
这个文本文件ex3.txt中的字段由不同数量的空格分隔。在这种情况下,我们可以将正则表达式作为 pandas.read_csv 的分隔符传递。这里可以用正则表达式 \s+ 来表示(windows下要加个转义符\),看如下代码:
import numpy as np
import pandas as pdresult = pd.read_csv("examples/ex3.txt", sep="\\s+")
print(result)
输出:
A | B | C | |
---|---|---|---|
aaa | -0.264438 | -1.026059 | -0.619500 |
bbb | 0.927272 | 0.302904 | -0.032399 |
ccc | -0.264273 | -0.386314 | -0.217601 |
ddd | -0.871858 | -0.348382 | 1.100491 |
由于列名少一个,因此pandas.read_csv推断在此特殊情况下,第一列应该是 DataFrame 的索引 。
我们再创建一个ex4.csv,第0、2、3行是注释行,其内容如下图:
我们在读取ex4.csv数据的时候需要忽略第0、2、3行注释内容,因此我们可以如下操作:
import numpy as np
import pandas as pdresult = pd.read_csv("examples/ex4.csv", skiprows=[0, 2, 3])
print(result)
用skiprows参数指定要跳过的行,输出结果如下:
a | b | c | d | message | |
---|---|---|---|---|---|
0 | 1 | 2 | 3 | 4 | hello |
1 | 5 | 6 | 7 | 8 | world |
2 | 9 | 10 | 11 | 12 | foo |
处理缺失值是文件数据读取过程中一个重要的部分。缺失数据通常是不存在,或是空字符串、或是由某个 sentinel (占位符)。默认情况下,pandas 使用一组常见的 sentinel替代这些缺失数据,例如 NaN 和 NULL 。我们创建一个ex5.csv文件来示例,这个文件的内容如下图:
import numpy as np
import pandas as pdresult = pd.read_csv("examples/ex5.csv")
print(result)
输出:
something | a | b | c | d | message | |
---|---|---|---|---|---|---|
0 | one | 1 | 2 | 3.0 | 4 | NaN |
1 | two | 5 | 6 | NaN | 8 | world |
2 | three | 9 | 10 | 11.0 | 12 | foo |
pandas 将缺失值输出为 NaN,因此我们在 result 中有两个缺失值NaN。可以用isna函数判断:
pd.isna(result) 输出:
something | a | b | c | d | message | |
---|---|---|---|---|---|---|
0 | False | False | False | False | False | True |
1 | False | False | False | True | False | False |
2 | False | False | False | False | False | False |
我们还以通过传递一个缺失值列表给na_values参数,指定哪些值是缺失值,例如我们将1和NULL指定为缺失值:
import pandas as pdresult = pd.read_csv("examples/ex5.csv", na_values=["NULL",'1'])print(result)
输出:
something | a | b | c | d | message | |
---|---|---|---|---|---|---|
0 | one | NaN | 2 | 3.0 | 4 | NaN |
1 | two | 5.0 | 6 | NaN | 8 | world |
2 | three | 9.0 | 10 | 11.0 | 12 | foo |
其中元素值1以及为null的元素,都用默认值NaN填充了。
另外,可以用keep_default_na=False设置缺失值进行isna判断时不为True,例如:
import pandas as pdresult2 = pd.read_csv("examples/ex5.csv", keep_default_na=False)
print(result2)
print(result2.isna())result3 = pd.read_csv("examples/ex5.csv", keep_default_na=False, na_values=["NA"])
print(result3)
print(result3.isna())
result2输出:
something | a | b | c | d | message | |
---|---|---|---|---|---|---|
0 | one | 1 | 2 | 3 | 4 | NA |
1 | two | 5 | 6 | 8 | world | |
2 | three | 9 | 10 | 11 | 12 | foo |
result2.isna()输出:
something | a | b | c | d | message | |
---|---|---|---|---|---|---|
0 | False | False | False | False | False | False |
1 | False | False | False | False | False | False |
2 | False | False | False | False | False | False |
result3输出:
something | a | b | c | d | message | |
---|---|---|---|---|---|---|
0 | one | 1 | 2 | 3 | 4 | NaN |
1 | two | 5 | 6 | 8 | world | |
2 | three | 9 | 10 | 11 | 12 | foo |
result3.isna()输出:
something | a | b | c | d | message | |
---|---|---|---|---|---|---|
0 | False | False | False | False | False | True |
1 | False | False | False | False | False | False |
2 | False | False | False | False | False | False |
从以上可以看出获取result2和result3数据的差别,大家可以自己琢磨下。
我们还可以为文件中的每一列指定不同的 NA 占位符,例如:
import pandas as pdsentinels = {"message": ["foo", "NA"], "something": ["two"]}
res = pd.read_csv("examples/ex5.csv", na_values=sentinels, keep_default_na=False)
print(res)
输出:
something | a | b | c | d | message | |
---|---|---|---|---|---|---|
0 | one | 1 | 2 | 3 | 4 | NaN |
1 | NaN | 5 | 6 | 8 | world | |
2 | three | 9 | 10 | 11 | 12 | NaN |
以下列表是一些 pandas.read_csv 函数常用参数,大家要学习列表中Description中内容,要动手写代码去试用 :
今天先学到这好累,下次学习分段读取文本文件