python用pandas数据加载、存储与文件格式的实例
数据加载、存储与文件格式
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:
importpandasaspd importnumpyasnp
#'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') printdf #输出结果如下: #abcdmessage #01234hello #15678world #29101112foo
(2)我们也可以用read_table,只不过需要指定分隔符而己:
df=pd.read_table('ex1.csv',sep=',') printdf #输出结果如下: #abcdmessage #01234hello #15678world #29101112foo
(3)读入文件可以让pandas为其分配默认的列名,也可以自己定义列名:
printpd.read_csv('ex1.csv',header=None) #输出结果如下: #01234 #0abcdmessage #11234hello #25678world #39101112foo printpd.read_csv('ex1.csv',names=['a','b','c','d','message']) #输出结果如下: #abcdmessage #0abcdmessage #11234hello #25678world #39101112foo
(4)假如希望将message列做成DataFrame的索引,也可以明确表示要将该列放到索引4的位置上,也可以通过index_col参数指定"message"
names=['a','b','c','d','message'] printpd.read_csv('ex1.csv',names=names) #输出结果如下: #abcdmessage #0abcdmessage #11234hello #25678world #39101112foo printpd.read_csv('ex1.csv',names=names,index_col='message') #输出结果如下: #abcd #message #messageabcd #hello1234 #world5678 #foo9101112
(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表示为行索引 printparsed #value1value2 #key1key2 #onea12 #b34 #c56 #d78 #twoa910 #b1112 #c1314 #d1516
(6)有些表示可能不是用固定的分隔符去分隔字段的(比如空白符或其它字符串)。对于这些情况,可以编写一个正则表达式来作为read_table
#的分隔符。看下面的文本文件 #'ex3.txt'的内容如下 #ABC, #aaa-0.264438-1.026059-0.619500 #bbb0.92838980.3928928-0.032388 #ccc-0.264327-0.386313-0.217601 #ddd-0.878218-0.3482381.1004919 printlist(open('ex3.txt')) #输出结果如下: #['ABC,\n', #'aaa-0.264438-1.026059-0.619500\n', #'bbb0.92838980.3928928-0.032388\n', #'ccc-0.264327-0.386313-0.217601\n', #'ddd-0.878218-0.3482381.1004919'] #该文件各个字段由数量不定的空白符分隔,则可以用正则表达式\s+表示: #正则表达式:\s表示空白符,\S非空白符,+表示后面会一直匹配下去。即\s+会匹配多个空格符 result=pd.read_table('ex3.txt',sep='\s+') printresult #输出结果如下: #ABC, #aaa-0.264438-1.026059-0.619500 #bbb0.9283900.392893-0.032388 #ccc-0.264327-0.386313-0.217601 #ddd-0.878218-0.3482381.100492 #注意:这里由于列名比数据行的数量少(即A,B,C三个列名,但是列的数据是4列),所以read_table推断第一列应该是DataFrame的索引。
(7)skiprows跳过文件的一些行,可以帮助处理各种各样的异形文件格式
#'ex4.csv'的内容如下: ##hey! #a,b,c,d,message ##justwantedtomakethinsmoredifficultforu ##whoreadsCSVfileswithcomputers,anyway? #1,2,3,4,hello #5,6,7,8,world #9,10,11,12,foo printpd.read_csv('ex4.txt',skiprows=[0,2,3]) #输出结果如下: #abcdmessage #01234hello #15678world #29101112foo
(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') printresult #输出结果如下: #somethingabcdmessage #0one123.04NaN #1two56NaN8world #2three91011.012foo printpd.isnull(result)#查看为缺失值 #输出结果如下: #somethingabcdmessage #0FalseFalseFalseFalseFalseTrue #1FalseFalseFalseTrueFalseFalse #2FalseFalseFalseFalseFalseFalse
(9)na_values可以接受一组用于表示缺失值的字符串:
result=pd.read_csv('ex5.csv',na_values=['NULL']) printresult #输出结果如下: #somethingabcdmessage #0one123.04NaN #1two56NaN8world #2three91011.012foo
(10)可以用一个字典为各列指定不同的NA标记值
sentinels={'message':['foo','NA'],'something':['two']}#将message列中的foo标成NA,something的two也标成NA printpd.read_csv('ex5.csv',na_values=sentinels) #输出结果如下: #somethingabcdmessage #0one123.04NaN #1NaN56NaN8world #2three91011.012NaN 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 千分位分隔符,如“,”或“。”
逐块读取文本文件:
在处理很大文件时,或找出大文件中的参数集以便于后续处理时,你可能只想读取文件的一小部分或逐块对文件进行迭代。
importpandasaspd importnumpyasnp frompandasimportSeries,DataFrame #'ex6.csv'的内容如下: ##Int64Index:10000entries,0to9999 #Datacolumns: #one10000non-nullvalues #two10000non-nullvalues #three10000non-nullvalues #four10000non-nullvalues #key10000non-nullvalues #dtypes:float64(4),object(1) printpd.read_csv('ex6.csv',nrows=5)#nrows=5取前6行,下标从0开始 #要逐块读取文件,需要设置chunksize(行数) chunker=pd.read_csv('ex6.csv',chunksize=1000) printchunker #输出结果如下: # #read_csv所返回的这个TextParser对象使你可以根据chunksize对文件进行逐块迭代。比如说: #我们可以迭代处理ex6.csv,将值计数聚合到"key"列中。 tot=Series([]) forpieceinchunker: 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) printtot#报key错误
将数据写到文本格式:
数据也可以被输出为分隔符格式文本
data=pd.read_csv('ex5.csv') #输出结果如下: printdata #输出结果如下: #somethingabcdmessage #0one123.04NaN #1two56NaN8world #2three91011.012foo
DataFrame的to_csv方法:
(1)数据写入:to_csv,利用DataFrame的to_csv方法,我们可以将数据写到一个以逗号分隔的文件中
printdata.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控制台,所以仅仅是打印出文本结果而己)
printdata.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'
printdata.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
printdata.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=[]
printdata.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开始 printdates #输出结果如下: #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方法
printSeries.from_csv('tseries.csv',parse_dates=True) #输出结果如下: #2000-01-010 #2000-01-021 #2000-01-032 #2000-01-043 #2000-01-054 #2000-01-065 #2000-01-076 #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.LocalPathoranyobjectwitharead()method(suchasafilehandleorStringIO) 可以是URL,可用URL类型包括:http,ftp,s3和文件。对于多文件正在准备中 本地文件读取实例:://localhost/path/to/table.csv sep:str,default‘,' 指定分隔符。如果不指定参数,则会尝试使用逗号分隔。分隔符长于一个字符并且不是‘\s+',将使用python的语法分析器。并且忽略数据中的逗号。正则表达式例子:'\r\t' delimiter:str,defaultNone 定界符,备选分隔符(如果指定该参数,则sep参数失效) delim_whitespace:boolean,defaultFalse. 指定空格(例如'‘或者'‘)是否作为分隔符使用,等效于设定sep='\s+'。如果这个参数设定为Ture那么delimiter参数失效。 在新版本0.18.1支持 header:intorlistofints,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,defaultNone 用于结果的列名列表,如果数据文件中没有列标题行,就需要执行header=None。默认列表中不能出现重复,除非设定参数mangle_dupe_cols=True。 index_col:intorsequenceorFalse,defaultNone 用作行索引的列编号或者列名,如果给定一个序列则有多个行索引。 如果文件不规则,行尾有分隔符,则可以设定index_col=False来是的pandas不适用第一列作为行索引。 usecols:array-like,defaultNone 返回一个数据子集,该列表中的值必须可以对应到文件中的位置(数字可以对应到指定的列)或者是字符传为文件中的列名。例如:usecols有效参数可能是[0,1,2]或者是[‘foo',‘bar',‘baz']。使用这个参数可以加快加载速度并降低内存消耗。 as_recarray:boolean,defaultFalse 不赞成使用:该参数会在未来版本移除。请使用pd.read_csv(...).to_records()替代。 返回一个Numpy的recarray来替代DataFrame。如果该参数设定为True。将会优先squeeze参数使用。并且行索引将不再可用,索引列也将被忽略。 squeeze:boolean,defaultFalse 如果文件值包含一列,则返回一个Series prefix:str,defaultNone 在没有列标题时,给列添加前缀。例如:添加‘X'成为X0,X1,... mangle_dupe_cols:boolean,defaultTrue 重复的列,将‘X'...'X'表示为‘X.0'...'X.N'。如果设定为false则会将所有重名列覆盖。 dtype:Typenameordictofcolumn->type,defaultNone 每列数据的数据类型。例如{‘a':np.float64,‘b':np.int32} engine:{‘c',‘python'},optional Parserenginetouse.TheCengineisfasterwhilethepythonengineiscurrentlymorefeature-complete. 使用的分析引擎。可以选择C或者是python。C引擎快但是Python引擎功能更加完备。 converters:dict,defaultNone 列转换函数的字典。key可以是列名或者列的序号。 true_values:list,defaultNone ValuestoconsiderasTrue false_values:list,defaultNone ValuestoconsiderasFalse skipinitialspace:boolean,defaultFalse 忽略分隔符后的空白(默认为False,即不忽略). skiprows:list-likeorinteger,defaultNone 需要忽略的行数(从文件开始处算起),或需要跳过的行号列表(从0开始)。 skipfooter:int,default0 从文件尾部开始忽略。(c引擎不支持) skip_footer:int,default0 不推荐使用:建议使用skipfooter,功能一样。 nrows:int,defaultNone 需要读取的行数(从文件头开始算起)。 na_values:scalar,str,list-like,ordict,defaultNone 一组用于替换NA/NaN的值。如果传参,需要制定特定列的空值。默认为‘1.#IND',‘1.#QNAN',‘N/A',‘NA',‘NULL',‘NaN',‘nan'`. keep_default_na:bool,defaultTrue 如果指定na_values参数,并且keep_default_na=False,那么默认的NaN将被覆盖,否则添加。 na_filter:boolean,defaultTrue 是否检查丢失值(空字符串或者是空值)。对于大文件来说数据集中没有空值,设定na_filter=False可以提升读取速度。 verbose:boolean,defaultFalse 是否打印各种解析器的输出信息,例如:“非数值列中缺失值的数量”等。 skip_blank_lines:boolean,defaultTrue 如果为True,则跳过空行;否则记为NaN。 parse_dates:booleanorlistofintsornamesorlistoflistsordict,defaultFalse boolean.True->解析索引 listofintsornames.e.g.If[1,2,3]->解析1,2,3列的值作为独立的日期列; listoflists.e.g.If[[1,3]]->合并1,3列作为一个日期列使用 dict,e.g.{‘foo':[1,3]}->将1,3列合并,并给合并后的列起名为"foo" infer_datetime_format:boolean,defaultFalse 如果设定为True并且parse_dates可用,那么pandas将尝试转换为日期类型,如果可以转换,转换方法并解析。在某些情况下会快5~10倍。 keep_date_col:boolean,defaultFalse 如果连接多列解析日期,则保持参与连接的列。默认为False。 date_parser:function,defaultNone 用于解析日期的函数,默认使用dateutil.parser.parser来做转换。Pandas尝试使用三种不同的方式解析,如果遇到问题则使用下一种方式。 1.使用一个或者多个arrays(由parse_dates指定)作为参数; 2.连接指定多列字符串作为一个列作为参数; 3.每行调用一次date_parser函数来解析一个或者多个字符串(由parse_dates指定)作为参数。 dayfirst:boolean,defaultFalse DD/MM格式的日期类型 iterator:boolean,defaultFalse 返回一个TextFileReader对象,以便逐块处理文件。 chunksize:int,defaultNone 文件块的大小,SeeIOToolsdocsformoreinformationoniteratorandchunksize. 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,defaultNone 千分位分割符,如“,”或者“." decimal:str,default‘.' 字符中的小数点(例如:欧洲数据使用',‘). float_precision:string,defaultNone SpecifieswhichconvertertheCengineshoulduseforfloating-pointvalues.TheoptionsareNonefortheordinaryconverter,highforthehigh-precisionconverter,andround_tripfortheround-tripconverter. 指定 lineterminator:str(length1),defaultNone 行分割符,只在C解析器下使用。 quotechar:str(length1),optional 引号,用作标识开始和解释的字符,引号内的分割符将被忽略。 quoting:intorcsv.QUOTE_*instance,default0 控制csv中的引号常量。可选QUOTE_MINIMAL(0),QUOTE_ALL(1),QUOTE_NONNUMERIC(2)orQUOTE_NONE(3) doublequote:boolean,defaultTrue 双引号,当单引号已经被定义,并且quoting参数不是QUOTE_NONE的时候,使用双引号表示引号内的元素作为一个元素使用。 escapechar:str(length1),defaultNone 当quoting为QUOTE_NONE时,指定一个字符使的不受分隔符限值。 comment:str,defaultNone 标识着多余的行不被解析。如果该字符出现在行首,这一行将被全部忽略。这个参数只能是一个字符,空行(就像skip_blank_lines=True)注释行被header和skiprows忽略一样。例如如果指定comment='#'解析‘#empty\na,b,c\n1,2,3'以header=0那么返回结果将是以'a,b,c'作为header。 encoding:str,defaultNone 指定字符集类型,通常指定为'utf-8'.ListofPythonstandardencodings dialect:strorcsv.Dialectinstance,defaultNone 如果没有指定特定的语言,如果sep大于一个字符则忽略。具体查看csv.Dialect文档 tupleize_cols:boolean,defaultFalse Leavealistoftuplesoncolumnsasis(defaultistoconverttoaMultiIndexonthecolumns) error_bad_lines:boolean,defaultTrue 如果一行包含太多的列,那么默认不会返回DataFrame,如果设置成false,那么会将改行剔除(只能在C解析器下使用)。 warn_bad_lines:boolean,defaultTrue 如果error_bad_lines=False,并且warn_bad_lines=True那么所有的“badlines”将会被输出(只能在C解析器下使用)。 low_memory:boolean,defaultTrue 分块加载到内存,再低内存消耗中解析。但是可能出现类型混淆。确保类型不被混淆需要设置为False。或者使用dtype参数指定类型。注意使用chunksize或者iterator参数分块读入会将整个文件读入到一个Dataframe,而忽略类型(只能在C解析器中有效) buffer_lines:int,defaultNone 不推荐使用,这个参数将会在未来版本移除,因为他的值在解析器中不推荐使用 compact_ints:boolean,defaultFalse 不推荐使用,这个参数将会在未来版本移除 如果设置compact_ints=True,那么任何有整数类型构成的列将被按照最小的整数类型存储,是否有符号将取决于use_unsigned参数 use_unsigned:boolean,defaultFalse 不推荐使用:这个参数将会在未来版本移除 如果整数列被压缩(i.e.compact_ints=True),指定被压缩的列是有符号还是无符号的。 memory_map:boolean,defaultFalse 如果使用的文件在内存内,那么直接map文件使用。使用这种方式可以避免文件再次进行IO操作。
手工处理分隔符格式:csvpython内置函数使用
大部分存储在磁盘上的表格型数据都能用pandas.read_table进行加载。然而有进还是需要手工处理。
由于接收到含有畸形行的文件而使read_table出毛病的情况并不少见。
对于任何单字符分隔符文件,可以直接使用python内置的csv模块。将任意己打开的文件或文件型的对象传给csv.reader
importcsv f=open('ex7.csv') reader=csv.reader(f) printreader #输出结果是一个对象:<_csv.readerobjectat0x10d7c7600> forlineinreader: printline #对这个reader进行迭代将会为每行产生一个元组 #输出结果如下: #['a','b','c'] #['1','2','3'] #['1','2','3','4']
为了使数据格式合乎要求,你需要对其做些调整
lines=list(csv.reader(open('ex7.csv'))) printlines #输出结果如下: #[['a','b','c'],['1','2','3'],['1','2','3','4']] printlines[0],lines[1] header,values=lines[0],lines[1:] printzip(*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:vforh,vinzip(header,zip(*values))} printdata_dict #输出结果如下:结果得到的是列表,不是元组 #{'a':('1','1'),'c':('3','3'),'b':('2','2')}
CSV文件的形式有很多。只需定义csv.Dialect的一个子类即可定义出新格式(如专门的分隔符、字符串引用约定、行结束符等)
classmy_dialect(csv.Dialect): lineterminator='\n' delimiter=';' quotechar='"' quoting=0 reader=csv.reader(f,dialect=my_dialect) printreader #输出结果如下: #<_csv.readerobjectat0x10628a6e0> withopen('mydata.csv','w')asf: 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}, ] withopen('stock.csv','w')asf: 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] withopen('stock.csv')asf: f_csv=csv.reader(f) headers=next(f_csv) printheaders #输出结果如下 #['Symbol','Price','Date','Time','Change','Volume'] forrowinf_csv: rows=tuple(convert(value)forconvert,valueinzip(col_types,row)) printrows #输出结果如下: #('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)] withopen('stock.csv')asf: forrowincsv.DictReader(f):#row指的是每一行 printrow row.update((key,coversion(row[key])) forkey,coversioninfield_types) #key:priceconversion:float,row.update(key)如果key在row中找到,则conversion(row[key])的值, #row[key]是指这个key的value值 printrow #输出如下:第一行是第一个printrow输出,下面一个才是转换后的printrow的输出 #{'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形式,即从磁盘中读取
importpandasaspd importnumpyasnp frompandasimportSeries,DataFrame importsys importjson
obj=""" {"name":"Wes", "places_lived":["UnitedStates","Spain","Germany"], "pet":null, "siblings":[{"name":"Scott","age":25,"pet":"Zuko"}, {"name":"Katie","age":33,"pet":"Cisco"}] } """ result=json.loads(obj) printresult #输出结果如下: {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'UnitedStates',u'Spain',u'Germany']}
相反json.dumps则将python对象转换成JSON格式。即写入
asjson=json.dumps(result) printasjson#输出结果与上面的result一样的json格式
将(一个或一组)json对象转换为DataFrame或其它便于分析的数据结构就由你决定了。
最简单方便的方式是:向DataFrame构造器传入一组Json对象,并选取数据字段的子集(即可以选一部分字段,也可以全部选定)
siblings=DataFrame(result['siblings'],columns=['name','age'])#选取result中的'siblings',列选取name,age两列 printsiblings #输出的结果如下: #nameage #0Scott25 #1Katie33
XML和HTML:Web信息收集
python有许多可以读写HTML和xml格式数据的库。lxml就是其中之一,它可以高效地解析大件。
lxml有多个编程接口。首先我们要用lxml.html处理HTML,然后再用lxml.objectify做一些XML处理。
HTML文件处理:
许多网站都将数据放到HTML表格中以便在浏览器中查看,但不能以一种更易于机器阅读的格式(如Json、HTML或XML)进行下载
(1)首先,找到你希望获取数据的URL,利用urllib2将其打开,然后用lxml解析得到的数据流。
importpandasaspd importnumpyasnp frompandasimportSeries,DataFrame importsys importjson fromurllib2importurlopen fromlxml.htmlimportparse fromlxmlimportobjectify
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标签的对象,以列表形式显示 printlinks[15:20] #输出结果如下:输出的是Html元素对象 #[, # , # , # , # ]
(2)要得到URL和链接文本,必须使用各对象的get方法(针对URL)和text_content方法(针对显示文本)
lnk=links[15] printlnk#显示的是下标为28的a标签的元素对象 printlnk.get('href')#用get方法得到以"href"的URL #输出结果如下:/quote/AAPL180601P00145000?p=AAPL180601P00145000 printlnk.text_content() #输出结果如下:AAPL180601P00145000 #使用下面这条列表推导式可获取文档中的全部URL urls=[lnk.get('href')forlnkindoc.findall('.//a')] printurls #输出结果如下: #['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') printtables #输出结果如下:是表格对象 #[, ] calls=tables[0] printcalls#输出的是对象 #每个表格都有标题行。tr是表格中的行,th表头单元格,td数据单元格 #先取出标题行 rows=calls.findall('.//tr') printrows#输出结果:也是行的元素对象如
#写一个函数:可以根据传入的参数得到相关表格中的数据 def_unpack(row,kind='td'): elts=row.findall('.//%s'%kind) return[val.text_content()forvalinelts] print_unpack(rows[1])#取数据单元格中的数据值 #输出结果如下:取rows[1]即第2行的数据 #['AAPL180608C00130000','2018-05-0411:45PMEDT','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和其它解析函数其实在内部都用到了它)
frompandas.io.parsersimportTextParser defparse_option_data(table): rows=table.findall('.//tr') header=_unpack(rows[0],kind='th') data=[_unpack(r)forrinrows[1:]] returnTextParser(data,names=header).get_chunk() aa=parse_option_data(table=tables) printDataFrame(aa)
利用lxml.objectify解析xml:可具体看另一篇专门介绍xml解析文件
aa.xml的内容如下:
1181251680 040000008200E000 1181572063 1800 Bringpizzahome 1234360800 1800 CheckMSOfficewebsiteforupdates 604f4792-eb89-478b-a14f-dd34d3cc6c21-1234360800 dismissed
defparseXML(xmlFile): """ Parsethexml :paramxmlFile: :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文件的内容 foraction,elemincontext: ifnotelem.text: text="None" else: text=elem.text printelem.tag+"=>"+text if__name__=="__main__": parseXML("aa.xml")
defparseXML(xmlFile): """ Parsethexml :paramxmlFile: :return: """ f=open(xmlFile) xml=f.read() f.close() tree=etree.parse(StringIO(xml)) context=etree.iterparse(StringIO(xml)) foraction,elemincontext: ifnotelem.text: text="None" else: text=elem.text printelem.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 #forupdates #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。
importpandasaspd importnumpyasnp frompandasimportSeries,DataFrame #二进制数据格式保存 frame=pd.read_csv('ex1.csv') printframe #输出结果如下: #abcdmessage #01234hello #15678world #29101112foo (1)可用to_pickle保存到磁盘 frame.to_pickle('frame_pickle') (2)还有一个也很好用的pickle函数pandas.load将数据读回到python,load也没有了,现在是read_pickle读取数据 #pd.load('frame_pickle')#load已经不能用了,现在是read_pickle printpd.read_pickle('frame_pickle')
警告:pickle仅建议用于短期存储格式。其原因是很难保证格式永远是稳定的。
今天的pickle的对象无法被后续版本的库unpickle出来。
(2)使用HDF5格式实现高效读写磁盘上以二进制格式存储的科学数据。
HDF5支持多种压缩器的即时压缩,能更高效地存储重复模式数据,对于那些非常大的无法直接放入内存的数据集,
HDF5就是不错的选择,因为它可以高效地分块读写。
python中的HDF5库有两个接口(即PyTables和h5py),h5py提供了一种直接而高级的HDF5API访问接口,
而PyTables则抽象了HDF5的许多细节以提供多种灵活的数据容器、表索引、查询功能以及对核外计算技术的某些支持。
importpandasaspd importnumpyasnp frompandasimportSeries,DataFrame importmatplotlib.pyplotasplt importtables #二进制数据格式保存 frame=pd.read_csv('ex1.csv') printframe #输出结果如下: #abcdmessage #01234hello #15678world #29101112foo #两个函数用于生成数据 random_state=np.random.RandomState(1999) defmake_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] returnmeans+np.random.randn(n_samples,2)*sigma,mu_choices defplot_clusters(data,clusters,name): plt.figure() colors=["#9b59b6","#3498db","#e74c3c","#2ecc71"] foriinnp.unique(clusters): plt.scatter(data[clusters==i,0],data[clusters==i,1],color=colors[i]) plt.axis('off') plt.title('Plotfrom%s'%name) #(1)数据写入到磁盘:open_file(文件名,'w'),create_array() data,clusters=make_random_cluster_points(10000) plot_clusters(data,clusters,"datainmemory") #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,"PyTablesArray") plt.show()
注意:HDF5不是数据库。它最适合用作”一次写多次读“的数据集。虽然数据可以在任何时候被添加到文件中,
但如果同时发生多个写操作,文件就可能会被破坏。
(3)读取MicrosoftExcel文件
pandas的ExcelFile类文件读取存储在Excel中表格型数据。由于ExcelFile用到了(python读取excel表格的包)xlrd和openpyxl包,所以先得安装它们才行。
#读取excel文件: xls_file=pd.ExcelFile('data.xls') #存放在某个工作表中的数据可以通过parse读取到DataFrame中 table=xls_file.parse('Sheet1')
3.使用HTML和WebAPI:request包中的get来读取数据
importpandasaspd importnumpyasnp frompandasimportSeries,DataFrame importmatplotlib.pyplotasplt importtables importrequests importjson #url='https://twitter.com/search?q=python+pandas' url='https://twitter.com/search?q=python%20pandas&src=typd' resp=requests.get(url) printresp.text data=json.loads(resp.text)#将resp转化成json格式 printdata printdata.keys() #用一个列表定义出感兴趣的tweet字段,然后将results列表传给DataFrame: tweet_fields=['created_at','from_user','id','text'] tweets=DataFrame(data['result'],columns=tweet_fields) printtweets.ix[7]
4.使用数据库
sqlite3数据库:读取数据库数据
importpandasaspd importnumpyasnp frompandasimportSeries,DataFrame importmatplotlib.pyplotasplt importtables importrequests importjson importsqlite3 (1)数据连接 query=""" CREATETABLEtest (aVARCHAR(20),bVARCHAR(20), cREAL,dINTEGER); """ 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='INSERTINTOtestVALUES(?,?,?,?)' con.executemany(stmt,data) con.commit() #查询数据,即读取数据库数据 cursor=con.execute('select*fromtest') rows=cursor.fetchall() printrows #输出结果如下: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属性中) printcursor.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]) printresult #输出结果如下: #abcd #0AtlantaGeorgia1.256 #1TallahasseeFlorida2.603 #2SacramentoCalifornia1.705 (5)上面的方法每查一次就得写一次,pandas有一个可以简化该过程的read_sql函数(位于pandas.io.sql模块)。 #只需传入select语句和连接对象即可。 importpandas.io.sqlassql #printsql.read_sql('select*fromtest',con) #或者直接用pd.read_sql不用先引入sql也一样的 df=pd.read_sql('select*fromtest',con) #输出结果如下: #abcd #0AtlantaGeorgia1.256 #1TallahasseeFlorida2.603 #2SacramentoCalifornia1.705 aa=DataFrame(df) printaa
mysql数据库:读取数据库数据
#读取mysql中的数据 importpymysql importconfigparser config=configparser (1)连接数据库 db=pymysql.connect("localhost","root", "root","imooc") cursor=db.cursor()#使用游标创建一个游标对象 (2)使用execute()方法执行sql查询 cursor.execute("select*fromtest1") data=cursor.fetchall() printdata #输出结果如下:4条数据,mysql取出的形式是元组 #((1,'tangseng',79,'xitianqujing','11783213,131313133,78271783918'), #(2,'zhubajie',61,'xitianqujing','787138912,83918933'), #(3,'sunwukong',91,'jitiandasheng','1378219389,17898932183,1841898344,1989839898'), #(4,'shaseng',71,'xitianqujing','1649281938,15089328109')) # (3)列名信息在cursor.description中,及列的其它信息也在 printcursor.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)) printtype(zip(*cursor.description)[0]) (4)将data放入DataFrame中,pandas必须是list才可以转化为DataFrame,而此处的Data是元组,故先转化为list才可以用 result=DataFrame(list(data),columns=zip(*cursor.description)[0]) printresult #输出结果如下: #iduser_namescoreover\ #01tangseng79xitianqujing #12zhubajie61xitianqujing #23sunwukong91jitiandasheng #34shaseng71xitianqujing # #mobile #011783213,131313133,78271783918 #1787138912,83918933 #21378219389,17898932183,1841898344,1989839898 #31649281938,15089328109 (5)可以用read_sql一次性获取: importpandas.io.sqlassql result=sql.read_sql('select*fromtest1',db) printresult #输出结果如下: #iduser_namescoreover\ #01tangseng79xitianqujing #12zhubajie61xitianqujing #23sunwukong91jitiandasheng #34shaseng71xitianqujing # #mobile #011783213,131313133,78271783918 #1787138912,83918933 #21378219389,17898932183,1841898344,1989839898 #31649281938,15089328109 db.close()
注意:(1)DataFrame接受转换的是list形式:sqlit3用fetchall取出的是列表,所以可以直接放在DataFrame中,而mysql取出来的是元组,故要先转化成list.
mongoDB数据库:读取数据库数据
NoSQL数据库有许多不同的形式。有些是简单的字典式键值对存储,另一些则是基于文档的(其中的基本单元是字典型的对象)。
frompandasimportSeries,DataFrame importpymongo importdatetime #importconfigparser #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":"Myfirstblogpost!", "tags":["mongodb","python","pymongo"], "date":datetime.datetime.utcnow()} (4)插入文件 posts=tweets.posts post_id=posts.insert_one(post).inserted_id (5)查询相关的数据 importpprint pprint.pprint(posts.find_one({"author":"Mike"})) (6)字典放入DataFrame中 p=DataFrame(post,columns=post.keys()) printp
以上这篇python用pandas数据加载、存储与文件格式的实例就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持毛票票。