數據加載、存儲與文件格式
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 pdimport numpy as np
#'ex1.csv'的內容如下:# a,b,c,d,message# 1,2,3,4,hello# 5,6,7,8,world# 9,10,11,12,foodf=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 fooprint 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 fooprint 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,16parsed=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.1004919print 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,fooprint 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,fooresult=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 fooprint 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也標成NAprint 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 NaNread_csv/read_table函數的參數:參數 說明path 表示文件系統位置、url、文件型對象的字符串sep或delimiter 用于對行各字段進行拆分的字符序列或正則表達式header 用作列名的行號。默認為0(第一行),如果沒有header行就應該設置為Noneindex_col 用作行索引的列編號或列名。可以是單個名稱/數字或多個名稱/數字組成的列表(層次化索引)names 用于結果的列名列表,結合header=Noneskiprows 需要忽略的行數(從文件開始處算起),或需要跳過的行號列表(從0開始)na_values 一組用于替換NA的值comment 用于將注釋信息從行尾拆分出去的字符(一個或多個)parse_dates 嘗試將數據解析為日期,默認為False.如果為True,則嘗試解析所有列。此外,還可以指定需要解析的一組 列號或列名。如果列表的元素為列表或元組,就會將多個列組合到一起再進行日期解析工作(例如,日期/時間 分別位于兩個列中)keep_date_col 如果連接多列解析日期,則保持參與連接的列。默認為False.converters 由列號/列名跟函數之間的映射關系組成的字典。例如,{‘foo':f}會對foo列的所有值應用函數fdayfirst 當解析有歧義的日期時,將其看做國際格式(例如:7/6/2012->June,7,2012).默認為Falsedate_parser 用于解析日期的函數nrows 需要讀取的行數(從文件開始處算起)iterator 返回一個TextParser以便逐塊讀取文件chunksize 文件塊的大小(用于迭代)skip_footer 需要忽略的行數(從文件末尾處算起)verbose 打印各種解析器輸出信息,比如“非數值列中缺失值的數量”等encoding 用于unicode的文本編碼格式。squeeze 如果數據經解析后僅含一列,則返回Seriesthousands 千分位分隔符,如“,”或“。”逐塊讀取文本文件:
在處理很大文件時,或找出大文件中的參數集以便于后續處理時,你可能只想讀取文件的一小部分或逐塊對文件進行迭代。
import pandas as pdimport numpy as npfrom 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為空時填充0tot=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 fooDataFrame的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行索引用datests.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: int64from_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'}, optionalParser 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 NoneValues to consider as True false_values : list, default NoneValues 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 Falseboolean. 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 FalseDD/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 NoneSpecifies 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 FalseLeave 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 csvf=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 = 0reader=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,935000csv產生的數據都是字符串類型的,它不會做任何其它類型的轉換,如果你需要做這樣的類型轉換,必須自己手動去實現:
#下面是一個在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_minimalskipinitialspace 忽略分隔符后面的空白符。默認Falsedoublequote 如何處理字段內的引用符號。如果為True,則雙寫。escapechar 用于對分隔符進行轉義的字符串。默認禁用
總結:
(1)對于那些使用復雜分隔符或多字符分隔符的文件,csv模塊就無能為力了。在這種情況下,就只能用字符串split方法或正則表達式方法re.split進行拆分和其它整理工作了。
(2)最后,如果你讀取CSV數據的目的是做數據分析和統計的話,你可能需要看一看 Pandas 包。Pandas 包含了一個非常方便的函數叫 pandas.read_csv() ,它可以加載CSV數據到一個 DataFrame 對象中去。 然后利用這個對象你就可以生成各種形式的統計、過濾數據以及執行其他高級操作了
json格式的讀取與寫入:
通過json.loads可將json字符串轉換成python形式,即從磁盤中讀取
import pandas as pdimport numpy as npfrom pandas import Series,DataFrameimport sysimport 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 pdimport numpy as npfrom pandas import Series,DataFrameimport sysimport json from urllib2 import urlopenfrom lxml.html import parsefrom 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=AAPL180601P00145000print lnk.text_content()#輸出結果如下:AAPL180601P00145000#使用下面這條列表推導式可獲取文檔中的全部URLurls=[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 TextParserdef 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+"=>"+textif __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+"=>"+textif __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 pdimport numpy as npfrom 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_pickleprint pd.read_pickle('frame_pickle')警告:pickle僅建議用于短期存儲格式。其原因是很難保證格式永遠是穩定的。
今天的pickle的對象無法被后續版本的庫unpickle出來。
(2)使用HDF5格式實現高效讀寫磁盤上以二進制格式存儲的科學數據。
HDF5支持多種壓縮器的即時壓縮,能更高效地存儲重復模式數據,對于那些非常大的無法直接放入內存的數據集,
HDF5就是不錯的選擇,因為它可以高效地分塊讀寫。
python中的HDF5庫有兩個接口(即PyTables和h5py),h5py提供了一種直接而高級的HDF5 API訪問接口,
而PyTables則抽象了HDF5的許多細節以提供多種靈活的數據容器、表索引、查詢功能以及對核外計算技術的某些支持。
import pandas as pdimport numpy as npfrom pandas import Series,DataFrameimport matplotlib.pyplot as pltimport 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 pdimport numpy as npfrom pandas import Series,DataFrameimport matplotlib.pyplot as pltimport tables import requestsimport 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 dataprint 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 pdimport numpy as npfrom pandas import Series,DataFrameimport matplotlib.pyplot as pltimport tables import requestsimport jsonimport 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)轉換為DataFrameresult=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 5aa=DataFrame(df)print aamysql數據庫:讀取數據庫數據
#讀取mysql中的數據import pymysqlimport configparserconfig =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 sqlresult=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,15089328109db.close()注意:(1)DataFrame接受轉換的是list形式:sqlit3用fetchall取出的是列表,所以可以直接放在DataFrame中,而mysql取出來的是元組,故要先轉化成list.
mongoDB數據庫:讀取數據庫數據
NoSQL數據庫有許多不同的形式。有些是簡單的字典式鍵值對存儲,另一些則是基于文檔的(其中的基本單元是字典型的對象)。
from pandas import Series,DataFrameimport pymongoimport datetime # import configparser# config =configparser (1)mongodb數據庫的連接con=pymongo.MongoClient('localhost',port=27017)(2)創建數據庫# tweets=con.test_database (3)創建集合:一組文件存儲在mongodb中,相當于數據庫的各個表# collection=tweets.test_collectionpost = {"author": "Mike", "text": "My first blog post!", "tags": ["mongodb", "python", "pymongo"], "date": datetime.datetime.utcnow()}(4)插入文件posts=tweets.postspost_id=posts.insert_one(post).inserted_id(5)查詢相關的數據import pprintpprint.pprint(posts.find_one({"author":"Mike"}))(6)字典放入DataFrame中p=DataFrame(post,columns=post.keys())print p以上這篇python用pandas數據加載、存儲與文件格式的實例就是小編分享給大家的全部內容了,希望能給大家一個參考,也希望大家多多支持VEVB武林網。
新聞熱點
疑難解答