时间:2020-12-16 08:42:37 | 栏目:Python代码 | 点击:次
数据加载、存储与文件格式
pandas提供了一些用于将表格型数据读取为DataFrame对象的函数。其中read_csv和read_talbe用得最多
pandas中的解析函数:
函数 说明
read_csv 从文件、URL、文件型对象中加载带分隔符的数据,默认分隔符为逗号
read_table 从文件、URL、文件型对象中加载带分隔符的数据。默认分隔符为制表符("\t")
read_fwf 读取定宽列格式数据(也就是说,没有分隔符)
read_clipboard 读取剪贴板中的数据,可以看做read_table的剪贴板版。在将网页转换为表格时很有用
下面介绍一下这些函数在将文本数据转换为DataFrame时所用到的一些技术。这些函数的选项可以划分为以下几个大类:
(1)索引:将一个或多个列当做返回的DataFrame处理,以及是否从文件、用户获取列名
(2)类型推断和数据转换:包括用户定义值的转换、缺失值标记列表等。(类型推断是这些函数中最重要的功能之一)
(3)日期解析:包括组合功能,比如将分散在多个列中的日期时间信息组合成结果中的单个列。
(4)迭代:支持对大文件进行逐块迭代。
(5)不规整数据问题:跳过一些行、页脚、注释或其他一些不重要的东西(比如成千上万个逗号隔开的数值数据)
1. 读写文本格式的数据:
(1)由于该文件以逗号分隔,所以我们可以使用read_csv将其读入一个DataFrame:
import pandas as pd import numpy as np
#'ex1.csv'的内容如下: # a,b,c,d,message # 1,2,3,4,hello # 5,6,7,8,world # 9,10,11,12,foo df=pd.read_csv('ex1.csv') print df #输出结果如下: # a b c d message # 0 1 2 3 4 hello # 1 5 6 7 8 world # 2 9 10 11 12 foo
(2)我们也可以用read_table,只不过需要指定分隔符而己:
df=pd.read_table('ex1.csv',sep=',') print df #输出结果如下: # a b c d message # 0 1 2 3 4 hello # 1 5 6 7 8 world # 2 9 10 11 12 foo
(3)读入文件可以让pandas为其分配默认的列名,也可以自己定义列名:
print pd.read_csv('ex1.csv',header=None) #输出结果如下: # 0 1 2 3 4 # 0 a b c d message # 1 1 2 3 4 hello # 2 5 6 7 8 world # 3 9 10 11 12 foo print pd.read_csv('ex1.csv',names=['a','b','c','d','message']) #输出结果如下: # a b c d message # 0 a b c d message # 1 1 2 3 4 hello # 2 5 6 7 8 world # 3 9 10 11 12 foo
(4)假如希望将message列做成DataFrame的索引,也可以明确表示要将该列放到索引4的位置上,也可以通过index_col参数指定"message"
names=['a','b','c','d','message'] print pd.read_csv('ex1.csv',names=names) #输出结果如下: # a b c d message # 0 a b c d message # 1 1 2 3 4 hello # 2 5 6 7 8 world # 3 9 10 11 12 foo print pd.read_csv('ex1.csv',names=names,index_col='message') #输出结果如下: # a b c d # message # message a b c d # hello 1 2 3 4 # world 5 6 7 8 # foo 9 10 11 12
(5)如果希望将多个列做成一个层次化索引,只需传入由列编号或列名组成的列表即可:
#'csv_mindex.csv'的内容如下: # key1,key2,value1,value2 # one,a,1,2 # one,b,3,4 # one,c,5,6 # one,d,7,8 # two,a,9,10 # two,b,11,12 # two,c,13,14 # two,d,15,16 parsed=pd.read_csv('csv_mindex.csv',index_col=['key1','key2']) #index_col表示为行索引 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
(6)有些表示可能不是用固定的分隔符去分隔字段的(比如空白符或其它字符串)。对于这些情况,可以编写一个正则表达式来作为read_table
# 的分隔符。看下面的文本文件 #'ex3.txt'的内容如下 # A B C, # aaa -0.264438 -1.026059 -0.619500 # bbb 0.9283898 0.3928928 -0.032388 # ccc -0.264327 -0.386313 -0.217601 # ddd -0.878218 -0.348238 1.1004919 print list(open('ex3.txt')) #输出结果如下: # [' A B C,\n', # 'aaa -0.264438 -1.026059 -0.619500\n', # 'bbb 0.9283898 0.3928928 -0.032388\n', # 'ccc -0.264327 -0.386313 -0.217601\n', # 'ddd -0.878218 -0.348238 1.1004919'] #该文件各个字段由数量不定的空白符分隔,则可以用正则表达式\s+表示: #正则表达式:\s表示空白符,\S非空白符,+表示后面会一直匹配下去。即\s+会匹配多个空格符 result=pd.read_table('ex3.txt',sep='\s+') print result #输出结果如下: # A B C, # aaa -0.264438 -1.026059 -0.619500 # bbb 0.928390 0.392893 -0.032388 # ccc -0.264327 -0.386313 -0.217601 # ddd -0.878218 -0.348238 1.100492 #注意:这里由于列名比数据行的数量少(即A,B,C三个列名,但是列的数据是4列),所以read_table推断第一列应该是DataFrame的索引。
(7)skiprows跳过文件的一些行,可以帮助处理各种各样的异形文件格式
#'ex4.csv'的内容如下: ##hey! # a,b,c,d,message # #just wanted to make thins more difficult for u # # who reads CSV files with computers,anyway? # 1,2,3,4,hello # 5,6,7,8,world # 9,10,11,12,foo print pd.read_csv('ex4.txt',skiprows=[0,2,3]) #输出结果如下: # a b c d message # 0 1 2 3 4 hello # 1 5 6 7 8 world # 2 9 10 11 12 foo
(8)缺失值处理是文件解析任务中的一个重要组成部分。缺失数据经常是要么没有(空字符串),要么用某个标记值表示。
#默认情况下,pandas会用一组经常出现的标记值进行识别,如NA,-1.#IND以及NULL等。 #'ex5.csv'的内容如下: # something,a,b,c,d,message # one,1,2,3,4,NA # two,5,6,,8,world # three,9,10,11,12,foo result=pd.read_csv('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 print pd.isnull(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
(9) na_values可以接受一组用于表示缺失值的字符串:
result=pd.read_csv('ex5.csv',na_values=['NULL']) 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
(10) 可以用一个字典为各列指定不同的NA标记值
sentinels={'message':['foo','NA'],'something':['two']} #将message列中的foo标成NA,something的two也标成NA print pd.read_csv('ex5.csv',na_values=sentinels) #输出结果如下: # something a b c d message # 0 one 1 2 3.0 4 NaN # 1 NaN 5 6 NaN 8 world # 2 three 9 10 11.0 12 NaN read_csv/read_table函数的参数:
参数 说明 path 表示文件系统位置、url、文件型对象的字符串 sep或delimiter 用于对行各字段进行拆分的字符序列或正则表达式 header 用作列名的行号。默认为0(第一行),如果没有header行就应该设置为None index_col 用作行索引的列编号或列名。可以是单个名称/数字或多个名称/数字组成的列表(层次化索引) names 用于结果的列名列表,结合header=None skiprows 需要忽略的行数(从文件开始处算起),或需要跳过的行号列表(从0开始) na_values 一组用于替换NA的值 comment 用于将注释信息从行尾拆分出去的字符(一个或多个) parse_dates 尝试将数据解析为日期,默认为False.如果为True,则尝试解析所有列。此外,还可以指定需要解析的一组 列号或列名。如果列表的元素为列表或元组,就会将多个列组合到一起再进行日期解析工作(例如,日期/时间 分别位于两个列中) keep_date_col 如果连接多列解析日期,则保持参与连接的列。默认为False. converters 由列号/列名跟函数之间的映射关系组成的字典。例如,{‘foo':f}会对foo列的所有值应用函数f dayfirst 当解析有歧义的日期时,将其看做国际格式(例如:7/6/2012->June,7,2012).默认为False date_parser 用于解析日期的函数 nrows 需要读取的行数(从文件开始处算起) iterator 返回一个TextParser以便逐块读取文件 chunksize 文件块的大小(用于迭代) skip_footer 需要忽略的行数(从文件末尾处算起) verbose 打印各种解析器输出信息,比如“非数值列中缺失值的数量”等 encoding 用于unicode的文本编码格式。 squeeze 如果数据经解析后仅含一列,则返回Series thousands 千分位分隔符,如“,”或“。”
逐块读取文本文件:
在处理很大文件时,或找出大文件中的参数集以便于后续处理时,你可能只想读取文件的一小部分或逐块对文件进行迭代。
import pandas as pd import numpy as np from pandas import Series,DataFrame #'ex6.csv'的内容如下: # <class 'pandas.core.frame.DataFrame'> # Int64Index:10000 entries, 0 to 9999 # Data columns: # one 10000 non-null values # two 10000 non-null values # three 10000 non-null values # four 10000 non-null values # key 10000 non-null values # dtypes: float64(4),object(1) print pd.read_csv('ex6.csv',nrows=5) #nrows=5取前6行,下标从0开始 #要逐块读取文件,需要设置chunksize(行数) chunker=pd.read_csv('ex6.csv',chunksize=1000) print chunker #输出结果如下: # <pandas.io.parsers.TextFileReader object at 0x102ebb5d0> #read_csv所返回的这个TextParser对象使你可以根据chunksize对文件进行逐块迭代。比如说: #我们可以迭代处理ex6.csv,将值计数聚合到"key"列中。 tot=Series([]) for piece in chunker: tot=tot.add(piece['key'].value_counts(),fill_value=0) #value_counts计算个数,fill_value为空时填充0 tot=tot.order(ascending=False) #此版本Series没有有order,可以换成sort_value # tot=tot.sort_value(ascending=False) print tot #报key错误
将数据写到文本格式:
数据也可以被输出为分隔符格式文本
data=pd.read_csv('ex5.csv') #输出结果如下: print data #输出结果如下: # 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
DataFrame的to_csv方法:
(1)数据写入:to_csv,利用DataFrame的to_csv方法,我们可以将数据写到一个以逗号分隔的文件中
print data.to_csv('out.csv') #out.csv的内容如下: # ,something,a,b,c,d,message # 0,one,1,2,3.0,4, # 1,two,5,6,,8,world # 2,three,9,10,11.0,12,foo
(2)当然也可以使用其他分隔符(由于这里直接写到sys.stdout控制台,所以仅仅是打印出文本结果而己)
print data.to_csv(sys.stdout,sep='|') #输出结果如下: # None # |something|a|b|c|d|message # 0|one|1|2|3.0|4| # 1|two|5|6||8|world # 2|three|9|10|11.0|12|foo # None
(3)缺失值在输出结果中会被表示为空字符串,若希望将其表示为别的标记值用na_sep='NULL'
print data.to_csv(sys.stdout,na_rep='NULL') #输出结果如下: # ,something,a,b,c,d,message # 0,one,1,2,3.0,4,NULL # 1,two,5,6,NULL,8,world # 2,three,9,10,11.0,12,foo # None
(4)如果没有设置其它选项,则会写出行和列的标签。当然,它们也都可以被禁用:index=False,header=False
print data.to_csv(sys.stdout,index=False,header=False) #行标签index,列标签header #输出结果如下: # one,1,2,3.0,4, # two,5,6,,8,world # three,9,10,11.0,12,foo # None
(5)还可以只写出一部分的列,并以你指定的顺序排序:index=False,columns=[]
print data.to_csv(sys.stdout,index=False,columns=['a','b','c']) #输出结果如下: # a,b,c # 1,2,3.0 # 5,6, # 9,10,11.0 # None
Series的to_csv方法:
(1)Series的to_csv方法,将Series写入到.csv文件中
dates=pd.date_range('1/1/2000',periods=7) #date_range可以生成时间序列,periods=7表示可以生成7个时间序列,从2000/1/1开始 print dates #输出结果如下: # DatetimeIndex(['2000-01-01', '2000-01-02', '2000-01-03', '2000-01-04', # '2000-01-05', '2000-01-06', '2000-01-07'], # dtype='datetime64[ns]', freq='D') ts=Series(np.arange(7),index=dates) #index行索引用dates ts.to_csv('tseries.csv') #tseries.csv的内容如下: # 2000-01-01,0 # 2000-01-02,1 # 2000-01-03,2 # 2000-01-04,3 # 2000-01-05,4 # 2000-01-06,5 # 2000-01-07,6
(2)read_csv也可以将csv文件读取为Series(Series.read_csv,而DataFrame则用pd.read_csv),但还有一个更为方更的from_csv方法
print Series.from_csv('tseries.csv',parse_dates=True) #输出结果如下: # 2000-01-01 0 # 2000-01-02 1 # 2000-01-03 2 # 2000-01-04 3 # 2000-01-05 4 # 2000-01-06 5 # 2000-01-07 6 # dtype: int64
from_csv和read_csv中参数整理如下:
pandas.read_csv参数整理 读取CSV(逗号分割)文件到DataFrame 也支持文件的部分导入和选择迭代 更多帮助参见:http://pandas.pydata.org/pandas-docs/stable/io.html 参数: filepath_or_buffer : str,pathlib。str, pathlib.Path, py._path.local.LocalPath or any object with a read() method (such as a file handle or StringIO) 可以是URL,可用URL类型包括:http, ftp, s3和文件。对于多文件正在准备中 本地文件读取实例:://localhost/path/to/table.csv sep : str, default ‘,' 指定分隔符。如果不指定参数,则会尝试使用逗号分隔。分隔符长于一个字符并且不是‘\s+',将使用python的语法分析器。并且忽略数据中的逗号。正则表达式例子:'\r\t' delimiter : str, default None 定界符,备选分隔符(如果指定该参数,则sep参数失效) delim_whitespace : boolean, default False. 指定空格(例如' ‘或者' ‘)是否作为分隔符使用,等效于设定sep='\s+'。如果这个参数设定为Ture那么delimiter 参数失效。 在新版本0.18.1支持 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表示第一行数据而不是文件的第一行。 names : array-like, default None 用于结果的列名列表,如果数据文件中没有列标题行,就需要执行header=None。默认列表中不能出现重复,除非设定参数mangle_dupe_cols=True。 index_col : int or sequence or False, default None 用作行索引的列编号或者列名,如果给定一个序列则有多个行索引。 如果文件不规则,行尾有分隔符,则可以设定index_col=False 来是的pandas不适用第一列作为行索引。 usecols : array-like, default None 返回一个数据子集,该列表中的值必须可以对应到文件中的位置(数字可以对应到指定的列)或者是字符传为文件中的列名。例如:usecols有效参数可能是 [0,1,2]或者是 [‘foo', ‘bar', ‘baz']。使用这个参数可以加快加载速度并降低内存消耗。 as_recarray : boolean, default False 不赞成使用:该参数会在未来版本移除。请使用pd.read_csv(...).to_records()替代。 返回一个Numpy的recarray来替代DataFrame。如果该参数设定为True。将会优先squeeze参数使用。并且行索引将不再可用,索引列也将被忽略。 squeeze : boolean, default False 如果文件值包含一列,则返回一个Series prefix : str, default None 在没有列标题时,给列添加前缀。例如:添加‘X' 成为 X0, X1, ... mangle_dupe_cols : boolean, default True 重复的列,将‘X'...'X'表示为‘X.0'...'X.N'。如果设定为false则会将所有重名列覆盖。 dtype : Type name or dict of column -> type, default None 每列数据的数据类型。例如 {‘a': np.float64, ‘b': np.int32} engine : {‘c', ‘python'}, optional Parser engine to use. The C engine is faster while the python engine is currently more feature-complete. 使用的分析引擎。可以选择C或者是python。C引擎快但是Python引擎功能更加完备。 converters : dict, default None 列转换函数的字典。key可以是列名或者列的序号。 true_values : list, default None Values to consider as True false_values : list, default None Values to consider as False skipinitialspace : boolean, default False 忽略分隔符后的空白(默认为False,即不忽略). skiprows : list-like or integer, default None 需要忽略的行数(从文件开始处算起),或需要跳过的行号列表(从0开始)。 skipfooter : int, default 0 从文件尾部开始忽略。 (c引擎不支持) skip_footer : int, default 0 不推荐使用:建议使用skipfooter ,功能一样。 nrows : int, default None 需要读取的行数(从文件头开始算起)。 na_values : scalar, str, list-like, or dict, default None 一组用于替换NA/NaN的值。如果传参,需要制定特定列的空值。默认为‘1.#IND', ‘1.#QNAN', ‘N/A', ‘NA', ‘NULL', ‘NaN', ‘nan'`. keep_default_na : bool, default True 如果指定na_values参数,并且keep_default_na=False,那么默认的NaN将被覆盖,否则添加。 na_filter : boolean, default True 是否检查丢失值(空字符串或者是空值)。对于大文件来说数据集中没有空值,设定na_filter=False可以提升读取速度。 verbose : boolean, default False 是否打印各种解析器的输出信息,例如:“非数值列中缺失值的数量”等。 skip_blank_lines : boolean, default True 如果为True,则跳过空行;否则记为NaN。 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" infer_datetime_format : boolean, default False 如果设定为True并且parse_dates 可用,那么pandas将尝试转换为日期类型,如果可以转换,转换方法并解析。在某些情况下会快5~10倍。 keep_date_col : boolean, default False 如果连接多列解析日期,则保持参与连接的列。默认为False。 date_parser : function, default None 用于解析日期的函数,默认使用dateutil.parser.parser来做转换。Pandas尝试使用三种不同的方式解析,如果遇到问题则使用下一种方式。 1.使用一个或者多个arrays(由parse_dates指定)作为参数; 2.连接指定多列字符串作为一个列作为参数; 3.每行调用一次date_parser函数来解析一个或者多个字符串(由parse_dates指定)作为参数。 dayfirst : boolean, default False DD/MM格式的日期类型 iterator : boolean, default False 返回一个TextFileReader 对象,以便逐块处理文件。 chunksize : int, default None 文件块的大小, See IO Tools docs for more informationon iterator and chunksize. compression : {‘infer', ‘gzip', ‘bz2', ‘zip', ‘xz', None}, default ‘infer' 直接使用磁盘上的压缩文件。如果使用infer参数,则使用 gzip, bz2, zip或者解压文件名中以‘.gz', ‘.bz2', ‘.zip', or ‘xz'这些为后缀的文件,否则不解压。如果使用zip,那么ZIP包中国必须只包含一个文件。设置为None则不解压。 新版本0.18.1版本支持zip和xz解压 thousands : str, default None 千分位分割符,如“,”或者“." decimal : str, default ‘.' 字符中的小数点 (例如:欧洲数据使用',‘). float_precision : string, default None Specifies which converter the C engine should use for floating-point values. The options are None for the ordinary converter, high for the high-precision converter, and round_trip for the round-trip converter. 指定 lineterminator : str (length 1), default None 行分割符,只在C解析器下使用。 quotechar : str (length 1), optional 引号,用作标识开始和解释的字符,引号内的分割符将被忽略。 quoting : int or csv.QUOTE_* instance, default 0 控制csv中的引号常量。可选 QUOTE_MINIMAL (0), QUOTE_ALL (1), QUOTE_NONNUMERIC (2) or QUOTE_NONE (3) doublequote : boolean, default True 双引号,当单引号已经被定义,并且quoting 参数不是QUOTE_NONE的时候,使用双引号表示引号内的元素作为一个元素使用。 escapechar : str (length 1), default None 当quoting 为QUOTE_NONE时,指定一个字符使的不受分隔符限值。 comment : str, default None 标识着多余的行不被解析。如果该字符出现在行首,这一行将被全部忽略。这个参数只能是一个字符,空行(就像skip_blank_lines=True)注释行被header和skiprows忽略一样。例如如果指定comment='#' 解析‘#empty\na,b,c\n1,2,3' 以header=0 那么返回结果将是以'a,b,c'作为header。 encoding : str, default None 指定字符集类型,通常指定为'utf-8'. List of Python standard encodings dialect : str or csv.Dialect instance, default None 如果没有指定特定的语言,如果sep大于一个字符则忽略。具体查看csv.Dialect 文档 tupleize_cols : boolean, default False Leave a list of tuples on columns as is (default is to convert to a Multi Index on the columns) error_bad_lines : boolean, default True 如果一行包含太多的列,那么默认不会返回DataFrame ,如果设置成false,那么会将改行剔除(只能在C解析器下使用)。 warn_bad_lines : boolean, default True 如果error_bad_lines =False,并且warn_bad_lines =True 那么所有的“bad lines”将会被输出(只能在C解析器下使用)。 low_memory : boolean, default True 分块加载到内存,再低内存消耗中解析。但是可能出现类型混淆。确保类型不被混淆需要设置为False。或者使用dtype 参数指定类型。注意使用chunksize 或者iterator 参数分块读入会将整个文件读入到一个Dataframe,而忽略类型(只能在C解析器中有效) buffer_lines : int, default None 不推荐使用,这个参数将会在未来版本移除,因为他的值在解析器中不推荐使用 compact_ints : boolean, default False 不推荐使用,这个参数将会在未来版本移除 如果设置compact_ints=True ,那么任何有整数类型构成的列将被按照最小的整数类型存储,是否有符号将取决于use_unsigned 参数 use_unsigned : boolean, default False 不推荐使用:这个参数将会在未来版本移除 如果整数列被压缩(i.e. compact_ints=True),指定被压缩的列是有符号还是无符号的。 memory_map : boolean, default False 如果使用的文件在内存内,那么直接map文件使用。使用这种方式可以避免文件再次进行IO操作。
手工处理分隔符格式:csv python内置函数使用
大部分存储在磁盘上的表格型数据都能用pandas.read_table进行加载。然而有进还是需要手工处理。
由于接收到含有畸形行的文件而使read_table出毛病的情况并不少见。
对于任何单字符分隔符文件,可以直接使用python内置的csv模块。将任意己打开的文件或文件型的对象传给csv.reader
import csv f=open('ex7.csv') reader=csv.reader(f) print reader #输出结果是一个对象:<_csv.reader object at 0x10d7c7600> for line in reader: print line #对这个reader进行迭代将会为每行产生一个元组 #输出结果如下: # ['a', 'b', 'c'] # ['1', '2', '3'] # ['1', '2', '3', '4']
为了使数据格式合乎要求,你需要对其做些调整
lines=list(csv.reader(open('ex7.csv'))) print lines #输出结果如下: # [['a', 'b', 'c'], ['1', '2', '3'], ['1', '2', '3', '4']] print lines[0],lines[1] header,values=lines[0],lines[1:] print zip(*values) #zip(iterable),将对象中对应的元素打包成一个个元组。a=[1,2,3] b=[2,4,5] zip(a,b)=[(1,2),(2,4),(3,5)] #输出结果如下: # [('1', '1'), ('2', '2'), ('3', '3')] data_dict={h:v for h, v in zip(header,zip(*values))} print data_dict #输出结果如下:结果得到的是列表,不是元组 # {'a': ('1', '1'), 'c': ('3', '3'), 'b': ('2', '2')}
CSV文件的形式有很多。只需定义csv.Dialect的一个子类即可定义出新格式(如专门的分隔符、字符串引用约定、行结束符等)
class my_dialect(csv.Dialect): lineterminator = '\n' delimiter = ';' quotechar = '"' quoting = 0 reader=csv.reader(f,dialect=my_dialect) print reader #输出结果如下: # <_csv.reader object at 0x10628a6e0> with open('mydata.csv','w')as f: writer=csv.writer(f,dialect=my_dialect) writer.writerow(('one','two','three')) writer.writerow(('1','2','3')) writer.writerow(('1', '2', '3')) #打开mydata.csv内容如下: # one;two;three # 1;2;3 # 1;2;3
各个csv语句的参数也可以用关键字的形式提供给csv.reader,无需定义子类:
reader=csv.reader(f,delimiter='|')
csv.writer用于手工输出分隔符文件,它接受一个己打开且可写的文件对象以及跟csv.reader相同的那些语句和选项:
#csv.writer先创建一个write对象,然后用writerow写入,可以一行行写入,也可以字典写入 headers = ['Symbol', 'Price', 'Date', 'Time', 'Change', 'Volume'] rows = [{'Symbol':'AA', 'Price':39.48, 'Date':'6/11/2007', 'Time':'9:36am', 'Change':-0.18, 'Volume':181800}, {'Symbol':'AIG', 'Price': 71.38, 'Date':'6/11/2007', 'Time':'9:36am', 'Change':-0.15, 'Volume': 195500}, {'Symbol':'AXP', 'Price': 62.58, 'Date':'6/11/2007', 'Time':'9:36am', 'Change':-0.46, 'Volume': 935000}, ] with open('stock.csv','w') as f: writer=csv.DictWriter(f,headers) writer.writeheader() writer.writerows(rows) #stock.csv的结果如下: # Symbol,Price,Date,Time,Change,Volume # AA,39.48,6/11/2007,9:36am,-0.18,181800 # AIG,71.38,6/11/2007,9:36am,-0.15,195500 # AXP,62.58,6/11/2007,9:36am,-0.46,935000
csv产生的数据都是字符串类型的,它不会做任何其它类型的转换,如果你需要做这样的类型转换,必须自己手动去实现:
#下面是一个在csv数据上执行其他类型转换的例子: col_types=[str,float,str,str,float,int] with open('stock.csv') as f: f_csv=csv.reader(f) headers=next(f_csv) print headers #输出结果如下 # ['Symbol', 'Price', 'Date', 'Time', 'Change', 'Volume'] for row in f_csv: rows=tuple(convert(value) for convert,value in zip(col_types,row)) print rows #输出结果如下: # ('AA', 39.48, '6/11/2007', '9:36am', -0.18, 181800) # ('AIG', 71.38, '6/11/2007', '9:36am', -0.15, 195500) # ('AXP', 62.58, '6/11/2007', '9:36am', -0.46, 935000) #下面是一个转换字典中特定字段的例子: field_types = [ ('Price', float), ('Change', float), ('Volume', int) ] with open('stock.csv') as f: for row in csv.DictReader(f): #row指的是每一行 print row row.update((key,coversion(row[key])) for key,coversion in field_types) #key:price conversion:float,row.update(key)如果key在row中找到,则conversion(row[key])的值, # row[key]是指这个key的value值 print row #输出如下:第一行是第一个print row输出,下面一个才是转换后的print row的输出 # {'Symbol': 'AA', 'Volume': '181800', 'Time': '9:36am', 'Date': '6/11/2007', 'Price': '39.48', 'Change': '-0.18'} # {'Symbol': 'AA', 'Volume': 181800, 'Time': '9:36am', 'Date': '6/11/2007', 'Price': 39.48, 'Change': -0.18}
csv 参数选项如下:
参数 说明 delimiter 用于分隔字段的单字符字符串。默认为“,” lineterminator 用于写操作的行结束符,默认为“\r\n” quotechar 用于带有特殊字符(如分隔符)的字段的引用符号。默认为“"” quoting 引用约定。可选值包括csv.quote_all(引用所有字段), csv.quote_minimal(只引用带有诸如分隔符之类特殊字符的字段)默认为quote_minimal skipinitialspace 忽略分隔符后面的空白符。默认False doublequote 如何处理字段内的引用符号。如果为True,则双写。 escapechar 用于对分隔符进行转义的字符串。默认禁用
总结:
(1)对于那些使用复杂分隔符或多字符分隔符的文件,csv模块就无能为力了。在这种情况下,就只能用字符串split方法或正则表达式方法re.split进行拆分和其它整理工作了。
(2)最后,如果你读取CSV数据的目的是做数据分析和统计的话,你可能需要看一看 Pandas 包。Pandas 包含了一个非常方便的函数叫 pandas.read_csv() ,它可以加载CSV数据到一个 DataFrame 对象中去。 然后利用这个对象你就可以生成各种形式的统计、过滤数据以及执行其他高级操作了
json格式的读取与写入:
通过json.loads可将json字符串转换成python形式,即从磁盘中读取
import pandas as pd import numpy as np from pandas import Series,DataFrame import sys import json
obj=""" {"name":"Wes", "places_lived":["United States","Spain","Germany"], "pet":null, "siblings":[{"name":"Scott","age":25,"pet":"Zuko"}, {"name":"Katie","age":33,"pet":"Cisco"}] } """ result=json.loads(obj) print result #输出结果如下: {u'pet': None, u'siblings': [{u'pet': u'Zuko', u'age': 25, u'name': u'Scott'}, {u'pet': u'Cisco', u'age': 33, u'name': u'Katie'}], u'name': u'Wes', u'places_lived': [u'United States', u'Spain', u'Germany']}
相反json.dumps则将python对象转换成JSON格式。即写入
asjson=json.dumps(result) print asjson #输出结果与上面的result一样的json格式
将(一个或一组)json对象转换为DataFrame或其它便于分析的数据结构就由你决定了。
最简单方便的方式是:向DataFrame构造器传入一组Json对象,并选取数据字段的子集(即可以选一部分字段,也可以全部选定)
siblings=DataFrame(result['siblings'],columns=['name','age']) #选取result中的'siblings',列选取name,age两列 print siblings #输出的结果如下: # name age # 0 Scott 25 # 1 Katie 33
XML和HTML:Web信息收集
python有许多可以读写HTML和xml格式数据的库。lxml就是其中之一,它可以高效地解析大件。
lxml有多个编程接口。首先我们要用lxml.html处理HTML,然后再用lxml.objectify做一些XML处理。
HTML文件处理:
许多网站都将数据放到HTML表格中以便在浏览器中查看,但不能以一种更易于机器阅读的格式(如Json、HTML或XML)进行下载
(1)首先,找到你希望获取数据的URL,利用urllib2将其打开,然后用lxml解析得到的数据流。
import pandas as pd import numpy as np from pandas import Series,DataFrame import sys import json from urllib2 import urlopen from lxml.html import parse from lxml import objectify
parsed=parse(urlopen('http://finance.yahoo.com/q/op?s=AAPL+Options')) doc=parsed.getroot() #通过这个对象可以获取特定类型的所有HTML标签(tag) #获取HTML中的链接是a标签的,可使用findall方法 links=doc.findall('.//a') #得到所有a标签的对象,以列表形式显示 print links[15:20] #输出结果如下:输出的是Html元素对象 # [<Element a at 0x1085206d8>, # <Element a at 0x108520730>, # <Element a at 0x108520788>, # <Element a at 0x1085207e0>, # <Element a at 0x108520838>]
(2)要得到URL和链接文本,必须使用各对象的get方法(针对URL)和text_content方法(针对显示文本)
lnk=links[15] print lnk #显示的是下标为28的a标签的元素对象 print lnk.get('href') #用get方法得到以"href"的URL #输出结果如下:/quote/AAPL180601P00145000?p=AAPL180601P00145000 print lnk.text_content() #输出结果如下:AAPL180601P00145000 #使用下面这条列表推导式可获取文档中的全部URL urls=[lnk.get('href') for lnk in doc.findall('.//a')] print urls #输出结果如下: # ['https://finance.yahoo.com/', '#Navigation', '#market-summary', '#Main', '#Aside', # 'https://mail.yahoo.com/?.intl=us&.lang=en-US&.partner=none&.src=finance', '/quote/AAPL?p=AAPL', # '/quote/AAPL/key-statistics?p=AAPL', '/quote/AAPL/profile?p=AAPL', '/quote/AAPL/financials?p=AAPL',]
(3)表格:从文档中找出正确表格,有些网站会给目标表格加上一个id属性。下面是两个分别放置看涨数据和跌数据的表格。
每个表格都有标题行。tr是表格中的行,th表头单元格,td数据单元格
tables=doc.findall('.//table') print tables #输出结果如下:是表格对象 # [<Element table at 0x10f1a09f0>, <Element table at 0x10f1a0a48>] calls=tables[0] print calls #输出的是对象 #每个表格都有标题行。tr是表格中的行,th表头单元格,td数据单元格 #先取出标题行 rows=calls.findall('.//tr') print rows #输出结果:也是行的元素对象如<Element tr at 0x108bffaa0>
#写一个函数:可以根据传入的参数得到相关表格中的数据 def _unpack(row,kind='td'): elts=row.findall('.//%s' % kind) return [val.text_content() for val in elts] print _unpack(rows[1]) #取数据单元格中的数据值 #输出结果如下:取rows[1]即第2行的数据 # ['AAPL180608C00130000', '2018-05-04 11:45PM EDT', '130.00', '36.90', '53.40', '54.70', '0.00', '-', '1', '1', '0.00%'] print _unpack(rows[1],kind='th') #取表头单元格的值,即列的标题 #输出结果:['Strike','Symbol','Last','Chg','Bid','Ask']
(4)把所有步骤结合起来,将数据转换为一个DataFrame。由于数值型数据仍然是字符串格式,所以我们希望将部分弄转换为浮点数格式。
虽然可以手工实现该功能,但是pandas就有一个TextParser类可以自动类型转换(read_csv和其它解析函数其实在内部都用到了它)
from pandas.io.parsers import TextParser def parse_option_data(table): rows=table.findall('.//tr') header=_unpack(rows[0],kind='th') data=[_unpack(r) for r in rows[1:]] return TextParser(data,names=header).get_chunk() aa=parse_option_data(table=tables) print DataFrame(aa)
利用lxml.objectify解析xml: 可具体看另一篇专门介绍xml解析文件
aa.xml的内容如下:
<?xml version="1.0" ?> <zAppointments reminder="15"> <appointment> <begin>1181251680</begin> <uid>040000008200E000</uid> <alarmTime>1181572063</alarmTime> <state></state> <location></location> <duration>1800</duration> <subject>Bring pizza home</subject> </appointment> <appointment> <begin>1234360800</begin> <duration>1800</duration> <subject>Check MS Office website for updates</subject> <location></location> <uid>604f4792-eb89-478b-a14f-dd34d3cc6c21-1234360800</uid> <state>dismissed</state> </appointment> </zAppointments>
def parseXML(xmlFile): """ Parse the xml :param xmlFile: :return: """ f=open(xmlFile) #1.先打开文件 xml=f.read() #2.读取文件内容 f.close() tree=etree.parse(StringIO(xml)) #3.用etree.parse解析xml文件的树结构 context=etree.iterparse(StringIO(xml)) #4.etree.iterparse迭代解析xml文件的内容 for action,elem in context: if not elem.text: text="None" else: text=elem.text print elem.tag+"=>"+text if __name__=="__main__": parseXML("aa.xml")
def parseXML(xmlFile): """ Parse the xml :param xmlFile: :return: """ f=open(xmlFile) xml=f.read() f.close() tree=etree.parse(StringIO(xml)) context=etree.iterparse(StringIO(xml)) for action,elem in context: if not elem.text: text="None" else: text=elem.text print elem.tag+"=>"+text if __name__=="__main__": parseXML("aa.xml") #输出结果如下: # begin = > 1181251680 # uid = > 040000008200E000 # alarmTime = > 1181572063 # state = > None # location = > None # duration = > 1800 # subject = > Bring # pizza # home # appointment = > # # begin = > 1234360800 # duration = > 1800 # subject = > Check # MS # Office # website # for updates # location = > None # uid = > 604 # f4792 - eb89 - 478 # b - a14f - dd34d3cc6c21 - 1234360800 # state = > dismissed # appointment = > # # zAppointments = >
2.二进制数据格式:写入与读取
(1)使用python内置的pickle序列化读取和存储数据
实现数据的二进制格式存储最简单的办法之一是使用python内置的pickle序列化。
为了使用方便,pandas对象都有一个用于将数据以pickle形式保存到磁盘上的to_pickle方法。
相反,从磁盘上读取read_pickle。
import pandas as pd import numpy as np from pandas import Series,DataFrame #二进制数据格式保存 frame=pd.read_csv('ex1.csv') print frame #输出结果如下: # a b c d message # 0 1 2 3 4 hello # 1 5 6 7 8 world # 2 9 10 11 12 foo (1)可用to_pickle保存到磁盘 frame.to_pickle('frame_pickle') (2)还有一个也很好用的pickle函数pandas.load将数据读回到python,load也没有了,现在是read_pickle读取数据 # pd.load('frame_pickle') #load已经不能用了,现在是read_pickle print pd.read_pickle('frame_pickle')
警告:pickle仅建议用于短期存储格式。其原因是很难保证格式永远是稳定的。
今天的pickle的对象无法被后续版本的库unpickle出来。
(2)使用HDF5格式实现高效读写磁盘上以二进制格式存储的科学数据。
HDF5支持多种压缩器的即时压缩,能更高效地存储重复模式数据,对于那些非常大的无法直接放入内存的数据集,
HDF5就是不错的选择,因为它可以高效地分块读写。
python中的HDF5库有两个接口(即PyTables和h5py),h5py提供了一种直接而高级的HDF5 API访问接口,
而PyTables则抽象了HDF5的许多细节以提供多种灵活的数据容器、表索引、查询功能以及对核外计算技术的某些支持。
import pandas as pd import numpy as np from pandas import Series,DataFrame import matplotlib.pyplot as plt import tables #二进制数据格式保存 frame=pd.read_csv('ex1.csv') print frame #输出结果如下: # a b c d message # 0 1 2 3 4 hello # 1 5 6 7 8 world # 2 9 10 11 12 foo #两个函数用于生成数据 random_state = np.random.RandomState(1999) def make_random_cluster_points(n_samples, random_state=random_state): mu_options = np.array([(-1, -1), (1, 1), (1, -1), (-1, 1)]) sigma = 0.2 mu_choices = random_state.randint(0, len(mu_options), size=n_samples) means = mu_options[mu_choices] return means + np.random.randn(n_samples, 2) * sigma, mu_choices def plot_clusters(data, clusters, name): plt.figure() colors = ["#9b59b6", "#3498db", "#e74c3c", "#2ecc71"] for i in np.unique(clusters): plt.scatter(data[clusters==i, 0], data[clusters==i, 1], color=colors[i]) plt.axis('off') plt.title('Plot from %s' % name) #(1)数据写入到磁盘:open_file(文件名,'w'),create_array() data, clusters = make_random_cluster_points(10000) plot_clusters(data, clusters, "data in memory") # plt.show() #画图展示 #PyTables存储数据到磁盘 sample_data,sample_clusters=make_random_cluster_points(10000) #调用函数生成数据 hdf5_path="my_data.hdf5" #写入的文件名 hdf5_file=tables.open_file(hdf5_path,mode='w') data_storage=hdf5_file.create_array(hdf5_file.root,'data',sample_data) #hdf5_file.root即"/",data为创建array文件名相当于"/data",data里存储的是sample_data的数据.data像文件名 clusters_storage=hdf5_file.create_array(hdf5_file.root,'clusters',sample_clusters) hdf5_file.close() #(2)数据的读取:open_file(文件名,'r'),hdf5_file.root.data[:] hdf5_path="my_data.hdf5" read_hdf5_file=tables.open_file(hdf5_path,mode='r') hdf5_data=read_hdf5_file.root.data[:] #读取read_hdf5_file根目录下的数据名称为data的全部数据 hdf5_clusters=read_hdf5_file.root.clusters[:] #读取read_hdf5_file根目录下的数据名称为clusters的全部数据 read_hdf5_file.close() plot_clusters(hdf5_data,hdf5_clusters,"PyTables Array") plt.show()
注意:HDF5不是数据库。它最适合用作”一次写多次读“的数据集。虽然数据可以在任何时候被添加到文件中,
但如果同时发生多个写操作,文件就可能会被破坏。
(3)读取Microsoft Excel文件
pandas的ExcelFile类文件读取存储在Excel中表格型数据。由于ExcelFile用到了(python读取excel表格的包)xlrd和openpyxl包,所以先得安装它们才行。
# 读取excel文件: xls_file=pd.ExcelFile('data.xls') #存放在某个工作表中的数据可以通过parse读取到DataFrame中 table=xls_file.parse('Sheet1')
3.使用HTML和Web API:request包中的get来读取数据
import pandas as pd import numpy as np from pandas import Series,DataFrame import matplotlib.pyplot as plt import tables import requests import json # url='https://twitter.com/search?q=python+pandas' url='https://twitter.com/search?q=python%20pandas&src=typd' resp=requests.get(url) print resp.text data=json.loads(resp.text) #将resp转化成json格式 print data print data.keys() #用一个列表定义出感兴趣的tweet字段,然后将results列表传给DataFrame: tweet_fields=['created_at','from_user','id','text'] tweets=DataFrame(data['result'],columns=tweet_fields) print tweets.ix[7]
4.使用数据库
sqlite3数据库:读取数据库数据
import pandas as pd import numpy as np from pandas import Series,DataFrame import matplotlib.pyplot as plt import tables import requests import json import sqlite3 (1)数据连接 query=""" CREATE TABLE test (a VARCHAR (20),b VARCHAR (20), c REAL, d INTEGER ); """ con=sqlite3.connect(':memory:') con.execute(query) con.commit() (2)插入数据 data=[('Atlanta','Georgia',1.25,6), ('Tallahassee','Florida',2.6,3), ('Sacramento','California',1.7,5)] stmt='INSERT INTO test VALUES(?,?,?,?)' con.executemany(stmt,data) con.commit() #查询数据,即读取数据库数据 cursor=con.execute('select * from test') rows=cursor.fetchall() print rows #输出结果如下:sqlite3取出的是列表 [(u'Atlanta', u'Georgia', 1.25, 6), (u'Tallahassee', u'Florida', 2.6, 3), (u'Sacramento', u'California', 1.7, 5)] (3)可以将这个元组列表传给DataFrame的构造器,但还需要列名(位于游标的description属性中) print cursor.description #输出结果如下: (('a', None, None, None, None, None, None), ('b', None, None, None, None, None, None), ('c', None, None, None, None, None, None), ('d', None, None, None, None, None, None)) (4)转换为DataFrame result=DataFrame(rows,columns=zip(*cursor.description)[0]) print result #输出结果如下: # a b c d # 0 Atlanta Georgia 1.25 6 # 1 Tallahassee Florida 2.60 3 # 2 Sacramento California 1.70 5 (5)上面的方法每查一次就得写一次,pandas有一个可以简化该过程的read_sql函数(位于pandas.io.sql模块)。 # 只需传入select语句和连接对象即可。 import pandas.io.sql as sql # print sql.read_sql('select * from test',con) #或者直接用pd.read_sql不用先引入sql也一样的 df= pd.read_sql('select * from test',con) #输出结果如下: # a b c d # 0 Atlanta Georgia 1.25 6 # 1 Tallahassee Florida 2.60 3 # 2 Sacramento California 1.70 5 aa=DataFrame(df) print aa
mysql数据库:读取数据库数据
#读取mysql中的数据 import pymysql import configparser config =configparser (1)连接数据库 db=pymysql.connect("localhost","root", "root","imooc") cursor=db.cursor() #使用游标创建一个游标对象 (2)使用execute()方法执行sql查询 cursor.execute("select * from test1") data=cursor.fetchall() print data #输出结果如下:4条数据,mysql取出的形式是元组 # ((1, 'tang seng', 79, 'xi tian qu jing', '11783213,131313133,78271783918'), # (2, 'zhu ba jie', 61, 'xi tian qu jing', '787138912,83918933'), # (3, 'sun wu kong', 91, 'ji tian da sheng', '1378219389,17898932183,1841898344,1989839898'), # (4, 'sha seng', 71, 'xi tian qu jing', '1649281938,15089328109')) # (3)列名信息在cursor.description中,及列的其它信息也在 print cursor.description # #查看结果如下: # ((u'id', 3, None, 11, 11, 0, 0), # (u'user_name', 253, None, 20, 20, 0, 1), # (u'score', 3, None, 2, 2, 0, 1), # (u'over', 253, None, 40, 40, 0, 1), # (u'mobile', 253, None, 100, 100, 0, 1)) print type(zip(*cursor.description)[0]) (4)将data放入DataFrame中,pandas必须是list才可以转化为DataFrame,而此处的Data是元组,故先转化为list才可以用 result=DataFrame(list(data),columns=zip(*cursor.description)[0]) print result #输出结果如下: # id user_name score over \ # 0 1 tang seng 79 xi tian qu jing # 1 2 zhu ba jie 61 xi tian qu jing # 2 3 sun wu kong 91 ji tian da sheng # 3 4 sha seng 71 xi tian qu jing # # mobile # 0 11783213,131313133,78271783918 # 1 787138912,83918933 # 2 1378219389,17898932183,1841898344,1989839898 # 3 1649281938,15089328109 (5)可以用read_sql一次性获取: import pandas.io.sql as sql result=sql.read_sql('select * from test1',db) print result #输出结果如下: # id user_name score over \ # 0 1 tang seng 79 xi tian qu jing # 1 2 zhu ba jie 61 xi tian qu jing # 2 3 sun wu kong 91 ji tian da sheng # 3 4 sha seng 71 xi tian qu jing # # mobile # 0 11783213,131313133,78271783918 # 1 787138912,83918933 # 2 1378219389,17898932183,1841898344,1989839898 # 3 1649281938,15089328109 db.close()
注意:(1)DataFrame接受转换的是list形式:sqlit3用fetchall取出的是列表,所以可以直接放在DataFrame中,而mysql取出来的是元组,故要先转化成list.
mongoDB数据库:读取数据库数据
NoSQL数据库有许多不同的形式。有些是简单的字典式键值对存储,另一些则是基于文档的(其中的基本单元是字典型的对象)。
from pandas import Series,DataFrame import pymongo import datetime # import configparser # config =configparser (1)mongodb数据库的连接 con=pymongo.MongoClient('localhost',port=27017) (2)创建数据库 # tweets=con.test_database (3)创建集合:一组文件存储在mongodb中,相当于数据库的各个表 # collection=tweets.test_collection post = {"author": "Mike", "text": "My first blog post!", "tags": ["mongodb", "python", "pymongo"], "date": datetime.datetime.utcnow()} (4)插入文件 posts=tweets.posts post_id=posts.insert_one(post).inserted_id (5)查询相关的数据 import pprint pprint.pprint(posts.find_one({"author":"Mike"})) (6)字典放入DataFrame中 p=DataFrame(post,columns=post.keys()) print p