在本期Python数据分析实战学习中,将从常见的数据获取方法入手,对常用的数据获取方式进行详细的介绍:
Open( ) 函数读取数据
Pandas 库读取数据
Numpy 库读取数据
第一招 Open( )函数读取数据
Python内置函数open( ),主要用来从文本中读取数据。
Python可以读取任何格式的文本数据。一般分为三个步骤:定义数据文件、创建文件对象、读取文件内容。将文件赋值给一个文件对象,为了后续操作更加便捷,减少代码冗余。
file_name1 = './test.txt'file_name2 = '/Users/jim/Documents/Python/test.txt'
file_name1 : 为相对路径,其要求需脚本路径与文件路径一致。 file_name2:为绝对路径,无其他要求。
1、语法
要以读文件的模式打开一个文件对象,使用Python内置的open( )函数,传入文件名和标示符,其意义在于后续的操作均是基于该对象产生的。
file_object = open(name [, mode][, buffering])
name: 要读取的文件名称。 mode: 打开文件的模式,选填。r, r+, w, w+, a, a+
使用最多。 buffering: 文件所需的缓冲区大小, 选填。0表示无缓冲, 1表示线路缓冲。
Mode | Describe |
---|---|
r | 以只读方式打开文件。文件的指针将会放在文件的开头。这是默认模式。 |
w | 打开一个文件只用于写入。如果该文件已存在则将其覆盖。如果该文件不存在,创建新文件。 |
a | 打开一个文件用于追加。如果该文件已存在,文件指针将会放在文件的结尾。也就是说,新的内容将会被写入到已有内容之后。如果该文件不存在,创建新文件进行写入。 |
rb | 以二进制格式打开一个文件用于只读。文件指针将会放在文件的开头。这是默认模式。 |
rb+ | 以二进制格式打开一个文件用于读写。文件指针将会放在文件的开头。 |
r+ | 打开一个文件用于读写。文件指针将会放在文件的开头。 |
w+ | 打开一个文件用于读写。如果该文件已存在则将其覆盖。如果该文件不存在,创建新文件。 |
a+ | 打开一个文件用于读写。如果该文件已存在,文件指针将会放在文件的结尾。文件打开时会是追加模式。如果该文件不存在,创建新文件用于读写。 |
wb | 以二进制格式打开一个文件只用于写入。如果该文件已存在则将其覆盖。如果该文件不存在,创建新文件。 |
wb+ | 以二进制格式打开一个文件用于读写。如果该文件已存在则将其覆盖。如果该文件不存在,创建新文件。 |
ab | 以二进制格式打开一个文件用于追加。如果该文件已存在,文件指针将会放在文件的结尾。也就是说,新的内容将会被写入到已有内容之后。如果该文件不存在,创建新文件进行写入。 |
ab+ | 以二进制格式打开一个文件用于追加。如果该文件已存在,文件指针将会放在文件的结尾。如果该文件不存在,创建新文件用于读写。 |
例
>>> file_object = open(file_name, 'r')# 文件不存在,即报错Traceback (most recent call last): File "", line 1, in FileNotFoundError: [Errno 2] No such file or directory: './test.txt'>>> file_object.read()'Hello world!'
2、Python基于文件对象分为3种方法
hon基于文件对象分为3种方法
Methods | Describe | Return |
---|---|---|
read | 读取文件中的全部数据,直到到达定义的size字节数上限 | 内容字符串,所有行合并为一个字符串 |
readline | 读取文件中的一行数据,直到到达定义的size字节数上限 | 内容字符串 |
readlines | 读取文件中的全部数据,直到到达定义的size字节数上限 | 内容列表,每行数据作为列表中的一个对象 |
例
# test.txt中有两行内容:"""line1: Hello world!line2: Life is short. I learn Python!""">>> file_object = open(file_name)>>> read_data = file_object.read()>>> print(read_data)line1: Hello world!line2: Life is short. I learn Python!>>> readline_data = file_object.readline()>>> print(readline_data)line1: Hello world!>>> readlines_data = file_object.readlines()>>> print(readlines_data)line1: Hello world!line2: Life is short. I learn Python!
遇到有些编码不规范的文件,你可能会遇到UnicodeDecodeError
,因为在文本文件中可能夹杂了一些非法编码的字符。遇到这种情况,open( )
函数还接收一个errors
参数,表示如果遇到编码错误后如何处理。最简单的方式是直接忽略:
file_object = open('/Users/jim/Documents/Python/gbk.txt', 'r', encoding='gbk', errors='ignore' )
readline
每次只读取一行数据,需配合seek
, next
等指针操作,才能完整遍历所有数据记录。
>>> fout = open('text.txt') # 获得文件对象>>> print(fout.tell()) # 输出指针位置0>>> line1 = fout.readline() # 获得文件第一行数据>>> print(line1) # 输出第一行数据line1: Hello world!>>> print(fin.tell()) # 输出指针位置21>>> line2 = fout.readline() # 获得文件第二行数据>>> print(line2) # 输出第二行数据line2: Life is short. I learn Python!>>> print(fout.tell()) # 输出指针位置>>> fout.close() # 关闭文件对象60
由于文件读写时都有可能产生IOError
,一旦出错,后面的fout.close()
就不会调用。可以使用try … finally
来保证无论是否出错都能正确地关闭文件:
>>> try:... file_object = open('./text.txt', 'r')... print(file_object.read())... finally:... if file_object:... file_object.close()
3、基于with的 文件打开方法 相信很多时候,在使用 open( )
函数时,总不是很方便。此时使用基于 with
的文件打开 方法,可以自动做上下文管理,而无需单独做close
操作,简单又方便:
例1 对单个文件对象操作时:
>>> with open( './test.txt', 'r' ) as fout:... print(fout.read())line1: Hello world!line2: Life is short. I learn Python!
例2 同时对多个文件对象操作,可以连续写open方法:
>>> with open( './test1.txt', 'r' ) as fout1, open( './test2.txt', 'r' ) as fout2:... content1 = fout1.read()... content2 = fout2.read()
调 用read()
会一次性读取文件的全部内容,如果文件有10G,内存就爆了。可以反复调用read(size)
方法,每次最多读取size
个字节的内容。 调用readline()
可以每次读取一行内容,调用readlines()
一次读取所有内容并按行返回list
。 如果文件很小,read()
一次性读取最方便;如果不能确定文件大小,反复调用read(size)
比较保险;如果是配置文件,调用readlines()
最方便。
csv
文本文件数据为例,对pandas读取数据进行详细对介绍。
>>> import pandas as pd>>> df = pd.read_csv(r"./test.csv" # 路径里面可以是中文,到时如果有特殊字符,可能会报错,建议路径全是英文。 , sep = ',' # 默认分隔符为, , header = 'infer' # 默认将第一行作为列名 ,header = None不要一第一行作为标题。 , encoding='gbk' # 默认用 UTF-8 进行解码,读取window系统建立的csv文件需改成`encoding='gbk'` , index_col=None ) >>> df.head(4) # df.head()默认显示前5行, 当然可以自己制定sh
输出结果:
常用参数说明:
sep : str, default ‘,’ 指定分隔符。如果不指定参数,则会尝试使用逗号分隔。分隔符长于一个字符并且不是‘\s+’,将使用python的语法分析器。并且忽略数据中的逗号。正则表达式例子:'\r\t'
header : int or list of ints, default ‘infer’ 指定行数用来作为列名,数据开始行数。如果文件中没有列名,则默认为0,否则设置为None。如果明确设定
header=0
就会替换掉原来存在列名。header
参数可以是一个list例如:[0,1,3],这个list表示将文件中的这些行作为列标题(意味着每一列有多个标题),介于中间的行将被忽略掉(例如本例中的2;本例中的数据1,2,4行将被作为多级标题出现,第3行数据将被丢弃,DataFrame的数据从第5行开始。)。注意:如果skip_blank_lines=True 那么header参数忽略注释行和空行,所以header=0表示第一行数据而不是文件的第一行。index_col : int or sequence or False, default None
用作行索引的列编号或者列名,如果给定一个序列则有多个行索引。 如果文件不规则,行尾有分隔符,则可以设定
index_col=False
来是的pandas不适用第一列作为行索引。encoding : str, default None 指定字符集类型,通常指定为'utf-8'.
dtype : Type name or dict of column -> type, default None 每列数据的数据类型。例如 {‘a’: np.float64, ‘b’: np.int32}
nrows : int, default None 需要读取的行数(从文件头开始算起)
skiprows : list-like or integer, default None 需要忽略的行数(从文件开始处算起),或需要跳过的行号列表(从0开始)。
low_memory : boolean, default True 分块加载到内存,再低内存消耗中解析。但是可能出现类型混淆。确保类型不被混淆需要设置为False。或者使用dtype 参数指定类型。注意使用chunksize 或者iterator 参数分块读入会将整个文件读入到一个DataFrame,而忽略类型(只能在C解析器中有效)
parse_dates : boolean or list of ints or names or list of lists or dict, default False
- boolean. True -> 解析索引
- list of ints or names. e.g. If [1, 2, 3] -> 解析1,2,3列的值作为独立的日期列;
- list of lists. e.g. If [[1, 3]] -> 合并1,3列作为一个日期列使用
- dict, e.g. {‘foo’ : [1, 3]} -> 将1,3列合并,并给合并后的列起名为"foo"
2、常见问题
路径内有中文csv
>>> import pandas as pd>>> #df=pd.read_csv("E:/测试文件夹/测试数据.csv")>>> f=open("E:/测试文件夹/测试数据.csv") # 解决方案>>> df=pd.read_csv(f)
window 中 shift+右键-->复制为路径
获取的文件路径
>>> import pandas as pd>>> # df=pd.read_csv("E:\测试文件夹\测试数据.csv")>>> df=pd.read_csv(r"E:\测试文件夹\测试数据.csv")
字符串前加 r
的作用
>>> "E:\测试文件夹\测试数据.csv"'E:\\测试文件夹\\测试数据.csv'>>> r"E:\测试文件夹\测试数据.csv"'E:\\测试文件夹\\测试数据.csv'>>> print("E:\测试文件夹\test.csv")E:\测试文件夹 est.csv >>> print(r"E:\测试文件夹\test.csv")E:\测试文件夹\test.csv
排除某些行
>>> import pandas as pd>>> df = pd.read_csv(r"./test.csv" ... , skiprows=3 # 要注意的是:排除前3行是skiprows=3 排除第3行是skiprows=[3]... , nrows=2... , encoding='gbk') >>> df
输出结果:
文件中有日期时间列
>>> import pandas as pd>>> df = pd.read_csv(r"./test.csv", encoding='gbk'... #, parse_dates=[3]... )>>> df.loc[0,'就诊日期']2018/6/15 >>> df = pd.read_csv(r"./test.csv", encoding='gbk'... , parse_dates=[3]... )>>> df.loc[0,'就诊日期']Timestamp('2018-06-15 00:00:00')
避坑指南:
有日期时间格式列的文件作为缓存文件,先用
test.to_csv('test.csv')
保存,再用pd.read_csv('./test.csv')
读取文件时。坑1:
index
列。保存文件时默认保存索引,读取文件时默认自动添加索引列,即将保存的索引作为第一列读取到DataFrame
。解决方案:
1,
test.to_csv('test.csv', index=False)
2,
pd.read_csv('./test.csv', index_col=0)
坑2:原本日期格式的列,保存到
csv
文件后仍为日期格式。但再次读取文件时将以字符串的格式读取到DataFrame
。解决方案:
1,
pd.read_csv('./test.csv', parse_dates=[3])
将特定的日期列解析为日期格式;2, 先使用默认值
file = pd.read_csv('./test.csv')
,再对特定的列进行格式转换。file.loc[:, column] = file.loc[:, column].map(lambda x: parse(x).date() if isinstance(file.loc[0, column], str) else x)
第三招 Numpy 库读取数据
Numpy读取数据方法与Pandas类似,其包括loadtxt, load, fromfile
Methods | Describe | Return |
---|---|---|
loadtxt | 从txt 文本中读取数据 |
从文件中读取的数组 |
load | 使用numpy 的load 方法可以读取numpy 专用的二进制数据文件,从npy , npz 或pickled 文件中加载数组或pickled 对象 |
从数据文件中读取的数据、元祖、字典等 |
fromfile | 使用numpy 的fromfile 方法可以读取简单的文本文件数据以及二进制数据 |
从文件中读取的数据 |
使用 loadtxt 方法读取数据文件
数据通常是一维或者二维的
语法
np.loadtxt( fname , dtype= , comments='#' , delimiter=None , converters=None , skiprows=0 , usecols=None , unpack=False , ndmin=0 , encoding='bytes' , max_rows=None ,)
常用参数说明:
fname : file, str, or pathlib.Path 文件或字符串, 必填项, 指要读取的文件名称或字符串, 支持压缩的数据文件, 包括gz
和bz
格式。 dtype : data-type, optional 数据类型, 选填, 默认为float。 comments : str or sequence of str, optional 字符串或字符串组成的列表, 选填,默认 #, 是表示注释字符集开始的标志。 delimiter : str, optional 字符串, 选填, 默认空格, 用来分隔多个列的分隔符, 如逗号、TAB符。 converters : dict, optional 字典, 选填, 默认为空, 用来将特定列的数据转换为字典中对应的函数的浮点型数据。如果第0列是一个date则'converters = {0: datestr2num} '; 'converters = {3: lambda s: float(s.strip() or 0)}'
skiprows : int, optional 跳过特定行数据, 选填, 默认为0, 用来跳过特定前N条记录。 usecols : int or sequence, optional 整数或元祖, 选填, 默认为空, 用来指定要读取数据的列, 如(1, 3, 6) unpack : bool, optional 布尔值, 选填, 默认为False, 用来指定是否转置, 如果为True, 则转置 ndmin : int, optional 整数型, 选填, 默认为0, 用来指定返回的数据至少包含特定维度的数组, 值域为0/1/2 encoding : str, optional 字符串, 选填, 用于解码inputfile的编码。不适用于输入流。特殊值"bytes"
允许向后兼容解决方案, 这可以确保接收到字节数组作为结果, 如果可能的话“latin1”编码的字符串到转换器。重写此值以接收unicode
数组, 并将字符串作为输入传递给转换器。如果没有设置, 使用系统默认值。默认值是"bytes"
。 max_rows : int, optional 整数, 选填, 默认为空, 在"skiprows"
行之后读取内容的"max_rows"
行。默认的就是读所有的行。
例
>>> import numpy as np # 导入numpy库>>> file_name = 'numpy_data.txt' # 定义数据文件>>> data = np.loadtxt(file_name, dtype='float32', delimiter=' ') # 获取数据>>> print(data) # 打印数据[[ 0. 1. 2. 3. 4.] [ 5. 6. 7. 8. 9.] [10. 11. 12. 13. 14.]]
使用 load 方法读取数据文件
numpy
的load
方法可以读取numpy
专用的二进制数据文件,从npy
, npz
或pickled
文件中加载数组或pickled
对象, 该文件通常基于numpy
的save
或savez
产生。
语法
np.load(file , mmap_mode=None , allow_pickle=False , fix_imports=True , encoding='ASCII')
file : file-like object, string, or pathlib.Path 类文件对象或字符串格式, 必填, 要读取的文或字符串。类文件对象需要支持seek()
和read()
方法。 mmap_mode : {None, 'r+', 'r', 'w+', 'c'}, optional 内存映射模式, 选填。 allow_pickle : bool, optional 布尔值, 选填, 默认为True
, 决定是否允许加载存储在npy
文件中的pickled
对象数组。 fix_imports : bool, optional 布尔值, 选填, 默认为True
, 只有在python3
上加载python2
生成的pickle
文件时才有用, 其中包括包含对象数组的npy/npz
文件。如果"fix_imports"
, 如果是True
,pickle
将尝试将旧的python2
名称映射到新名称在python3
中使用。 encoding : str, optional 在读取Python 2
字符串时使用什么编码。加载python2
生成了python3
中的pickle
文件时才有用, 其中包括包含对象数组的npy/npz
文件。除了latin1
,"ASCII"
和"bytes"
是不允许的, 因为它们会破坏数字数据。默认值:"ASCII"
例
>>> import numpy as np # 导入numpy库>>> write_data = np.array([[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]]) # 定义要存储的数据>>> np.save('load_data', write_data) # 保存为npy数据文件>>> read_data = np.load('load_data.npy') # 读取npy文件>>> print(read_data) # 输出读取的数据[[ 1 2 3 4] [ 5 6 7 8] [ 9 10 11 12]]
使用 fromfile 方法读取数据文件
语法
fromfile(file, dtype=float, count=-1, sep='', offset=0)
file : file or str or Path 文件或字符串或路径 dtype : data-type, optional 数据类型, 选填, 默认为float。 count : int 整数型, 读取数据的数量, -1意味着读取所有的数据。 sep : str 字符串, 如果文件是文本文件, 那么该值为数据间的分隔符。空("")分隔符表示该文件应该作为二进制文件处理。分隔符中的空格(" ")匹配零个或多个空格字符。仅由空格组成的分隔符必须至少匹配一个空白。
例
>>> import numpy as np # 导入numpy库>>> file_name = 'numpy_data.txt' # 定义数据文件>>> data = np.loadtxt(file_name, dtype='float32', delimiter=' ') # 获取数据>>> tofile_name = 'binary' # 定义导出二进制文件名>>> data.tofile(tofile_name) # 导出二进制文件>>> fromfile_data = np.fromfile(tofile_name, dtype='float32') # 读取二进制文件>>> print(fromfile_data) # 打印数据[ 0. 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14.]
另外,使用Python读取Excel文件,除了使用pandas.read_excel()
,还是采用专门用于读取Excel的第三方库,最常用的是xlrd。