用Pandas讀取CSV,看這篇就夠了
01 語法
基本語法如下,pd為導入Pandas模塊的別名:
- pd.read_csv(filepath_or_buffer: Union[str, pathlib.Path, IO[~AnyStr]],
- sep=',', delimiter=None, header='infer', names=None, index_col=None,
- usecols=None, squeeze=False, prefix=None, mangle_dupe_cols=True,
- dtype=None, engine=None, converters=None, true_values=None,
- false_values=None, skipinitialspace=False, skiprows=None,
- skipfooter=0, nrows=None, na_values=None, keep_default_na=True,
- na_filter=True, verbose=False, skip_blank_lines=True,
- parse_dates=False, infer_datetime_format=False,
- keep_date_col=False, date_parser=None, dayfirst=False,
- cache_dates=True, iterator=False, chunksize=None,
- compression='infer', thousands=None, decimal: str = '.',
- lineterminator=None, quotechar='"', quoting=0,
- doublequote=True, escapechar=None, comment=None,
- encoding=None, dialect=None, error_bad_lines=True,
- warn_bad_lines=True, delim_whitespace=False,
- low_memory=True, memory_map=False, float_precision=None)
一般情況下,會將讀取到的數(shù)據(jù)返回一個DataFrame,當然按照參數(shù)的要求會返回指定的類型。
02 數(shù)據(jù)內(nèi)容
filepath_or_buffer為第一個參數(shù),沒有默認值,也不能為空,根據(jù)Python的語法,第一個參數(shù)傳參時可以不寫參數(shù)名??梢詡魑募窂剑?nbsp;
- # 支持文件路徑或者文件緩沖對象
- # 本地相對路徑
- pd.read_csv('data/data.csv') # 注意目錄層級
- pd.read_csv('data.csv') # 如果文件與代碼文件在同一目錄下
- pd.read_csv('data/my/my.data') # CSV文件的擴展名不一定是.csv
- # 本地絕對路徑
- pd.read_csv('/user/gairuo/data/data.csv')
- # 使用URL
- pd.read_csv('https://www.gairuo.com/file/data/dataset/GDP-China.csv')
需要注意的是,Mac中和Windows中路徑的寫法不一樣,上例是Mac中的寫法,Windows中的相對路徑和絕對路徑需要分別換成類似'data\data.csv'和'E: \data\data.csv'的形式。另外,路徑盡量不要使用中文,否則程序容易報錯,這意味著你存放數(shù)據(jù)文件的目錄要盡量用英文命名。
可以傳數(shù)據(jù)字符串,即CSV中的數(shù)據(jù)字符以字符串形式直接傳入:
- from io import StringIO
- data = ('col1,col2,col3\n'
- 'a,b,1\n'
- 'a,b,2\n'
- 'c,d,3')
- pd.read_csv(StringIO(data))
- pd.read_csv(StringIO(data), dtype=object)
也可以傳入字節(jié)數(shù)據(jù):
- from io import BytesIO
- data = (b'word,length\n'
- b'Tr\xc3\xa4umen,7\n'
- b'Gr\xc3\xbc\xc3\x9fe,5')
- pd.read_csv(BytesIO(data))
03 分隔符
sep參數(shù)是字符型的,代表每行數(shù)據(jù)內(nèi)容的分隔符號,默認是逗號,另外常見的還有制表符(\t)、空格等,根據(jù)數(shù)據(jù)的實際情況傳值。
- # 數(shù)據(jù)分隔符默認是逗號,可以指定為其他符號
- pd.read_csv(data, sep='\t') # 制表符分隔tab
- pd.read_table(data) # read_table 默認是制表符分隔tab
- pd.read_csv(data, sep='|') # 制表符分隔tab
- pd.read_csv(data,sep="(?<!a)\|(?!1)", engine='python') # 使用正則表達式
pd.read_csv還提供了一個參數(shù)名為delimiter的定界符,這是一個備選分隔符,是sep的別名,效果和sep一樣。如果指定該參數(shù),則sep參數(shù)失效。
04 表頭
header參數(shù)支持整型和由整型組成的列表,指定第幾行是表頭,默認會自動推斷把第一行作為表頭。
- pd.read_csv(data, header=0) # 第一行
- pd.read_csv(data, header=None) # 沒有表頭
- pd.read_csv(data, header=[0,1,3]) # 多層索引MultiIndex
- 注意:如果skip_blank_lines=True,header參數(shù)將忽略空行和注釋行, 因此header=0表示第一行數(shù)據(jù)而非文件的第一行。
05 列名
names用來指定列的名稱,它是一個類似列表的序列,與數(shù)據(jù)一一對應。如果文件不包含列名,那么應該設置header=None,列名列表中不允許有重復值。
- pd.read_csv(data, names=['列1', '列2']) # 指定列名列表
- pd.read_csv(data, names=['列1', '列2'], header=None)
06 索引
index_col用來指定索引列,可以是行索引的列編號或者列名,如果給定一個序列,則有多個行索引。Pandas不會自動將第一列作為索引,不指定時會自動使用以0開始的自然索引。
- # 支持int、str、int序列、str序列、False,默認為None
- pd.read_csv(data, index_col=False) # 不再使用首列作為索引
- pd.read_csv(data, index_col=0) # 第幾列是索引
- pd.read_csv(data, index_col='年份') # 指定列名
- pd.read_csv(data, index_col=['a','b']) # 多個索引
- pd.read_csv(data, index_col=[0, 3]) # 按列索引指定多個索引
07 使用部分列
如果只使用數(shù)據(jù)的部分列,可以用usecols來指定,這樣可以加快加載速度并降低內(nèi)存消耗。
- # 支持類似列表的序列和可調(diào)用對象
- # 讀取部分列
- pd.read_csv(data, usecols=[0,4,3]) # 按索引只讀取指定列,與順序無關
- pd.read_csv(data, usecols=['列1', '列5']) # 按列名,列名必須存在
- # 指定列順序,其實是df的篩選功能
- pd.read_csv(data, usecols=['列1', '列5'])[['列5', '列1']]
- # 以下用callable方式可以巧妙指定順序,in后面的是我們要的順序
- pd.read_csv(data, usecols=lambda x: x.upper() in ['COL3', 'COL1'])
08 返回序列
將squeeze設置為True,如果文件只包含一列,則返回一個Series,如果有多列,則還是返回DataFrame。
- # 布爾型,默認為False
- # 下例只取一列,會返回一個Series
- pd.read_csv(data, usecols=[0], squeeze=True)
- # 有兩列則還是df
- pd.read_csv(data, usecols=[0, 2], squeeze=True)
09 表頭前綴
如果原始數(shù)據(jù)沒有列名,可以指定一個前綴加序數(shù)的名稱,如n0、n1,通過prefix參數(shù)指定前綴。
- # 格式為字符型str
- # 表頭為c_0、c_2
- pd.read_csv(data, prefix='c_', header=None)
10 處理重復列名
如果該參數(shù)為True,當列名有重復時,解析列名將變?yōu)閄, X.1, …, X.N,而不是X, …, X。如果該參數(shù)為False,那么當列名中有重復時,前列將會被后列覆蓋。
- # 布爾型,默認為True
- data = 'a,b,a\n0,1,2\n3,4,5'
- pd.read_csv(StringIO(data), mangle_dupe_cols=True)
- # 表頭為a b a.1
- # False會報ValueError錯誤
11 數(shù)據(jù)類型
- dtype可以指定各數(shù)據(jù)列的數(shù)據(jù)類型。
- # 傳入類型名稱,或者以列名為鍵、以指定類型為值的字典
- pd.read_csv(data, dtype=np.float64) # 所有數(shù)據(jù)均為此數(shù)據(jù)類型
- pd.read_csv(data, dtype={'c1':np.float64, 'c2': str}) # 指定字段的類型
- pd.read_csv(data, dtype=[datetime, datetime, str, float]) # 依次指定
12 引擎
使用的分析引擎可以選擇C或Python。C語言的速度最快,Python語言的功能最為完善,一般情況下,不需要另行指定。
- # 格式為engine=None,其中可選值有{'c', 'python'}
- pd.read_csv(data, engine='c')
13 列數(shù)據(jù)處理
使用converters參數(shù)對列的數(shù)據(jù)進行轉(zhuǎn)換,參數(shù)中指定列名與針對此列的處理函數(shù),最終以字典的形式傳入,字典的鍵可以是列名或者列的序號。
- # 字典格式,默認為None
- data = 'x,y\na,1\nb,2'
- def foo(p):
- return p+'s'
- # x應用函數(shù),y使用lambda
- pd.read_csv(StringIO(data), converters={'x': foo,
- 'y': lambda x: x*3})
- # 使用列索引
- pd.read_csv(StringIO(data),
- converters={0: foo, 1: lambda x: x*3})
14 真假值轉(zhuǎn)換
使用true_values和false_values將指定的文本內(nèi)容轉(zhuǎn)換為True或False,可以用列表指定多個值。
- # 列表,默認為None
- data = ('a,b,c\n1,Yes,2\n3,No,4')
- pd.read_csv(StringIO(data),
- true_values=['Yes'], false_values=['No'])
15 跳過指定行
如下跳過需要忽略的行數(shù)(從文件開始處算起)或需要忽略的行號列表(從0開始):
- # 類似列表的序列或者可調(diào)用對象
- # 跳過前三行
- pd.read_csv(data, skiprows=2)
- # 跳過前三行
- pd.read_csv(data, skiprows=range(2))
- # 跳過指定行
- pd.read_csv(data, skiprows=[24,234,141])
- # 跳過指定行
- pd.read_csv(data, skiprows=np.array([2, 6, 11]))
- # 隔行跳過
- pd.read_csv(data, skiprows=lambda x: x % 2 != 0)
尾部跳過,從文件尾部開始忽略,C引擎不支持。
- # int類型, 默認為0
- pd.read_csv(filename, skipfooter=1) # 最后一行不加載
skip_blank_lines指定是否跳過空行,如果為True,則跳過空行,否則數(shù)據(jù)記為NaN。
- # 布爾型,默認為True
- # 不跳過空行
- pd.read_csv(data, skip_blank_lines=False)
如果skip_blank_lines=True,header參數(shù)將忽略空行和注釋行, 因此header=0表示第一行數(shù)據(jù)而非文件的第一行。
16 讀取指定行
nrows參數(shù)用于指定需要讀取的行數(shù),從文件第一行算起,經(jīng)常用于較大的數(shù)據(jù),先取部分進行代碼編寫。
- # int類型,默認為None
- pd.read_csv(data, nrows=1000)
17 空值替換
na_values參數(shù)的值是一組用于替換NA/NaN的值。如果傳參,需要指定特定列的空值。以下值默認會被認定為空值:
- ['-1.#IND', '1.#QNAN', '1.#IND', '-1.#QNAN',
- '#N/A N/A', '#N/A', 'N/A', 'n/a', 'NA',
- '#NA', 'NULL', 'null', 'NaN', '-NaN',
- 'nan', '-nan', '']
使用na_values時需要關注下面keep_default_na的配合使用和影響:
- # 可傳入標量、字符串、類似列表序列和字典,默認為None
- # 5和5.0會被認為是NaN
- pd.read_csv(data, na_values=[5])
- # ?會被認為是NaN
- pd.read_csv(data, na_values='?')
- # 空值為NaN
- pd.read_csv(data, keep_default_na=False, na_values=[""])
- # 字符NA和字符0會被認為是NaN
- pd.read_csv(data, keep_default_na=False, na_values=["NA", "0"])
- # Nope會被認為是NaN
- pd.read_csv(data, na_values=["Nope"])
- # a、b、c均被認為是NaN,等于na_values=['a','b','c']
- pd.read_csv(data, na_values='abc')
- # 指定列的指定值會被認為是NaN
- pd.read_csv(data, na_values={'c':3, 1:[2,5]})
18 保留默認空值
分析數(shù)據(jù)時是否包含默認的NaN值,是否自動識別。如果指定na_values參數(shù),并且 keep_default_na=False,那么默認的NaN將被覆蓋,否則添加。keep_default_na和na_values的關系見表3-2。
▼表3-2 keep_default_na和na_values的取值邏輯關系
- 說明:如果na_filter為False(默認為True),那么keep_default_na和na_values參數(shù)均無效。
- # 布爾型,默認為True
- # 不自動識別空值
- pd.read_csv(data, keep_default_na=False)
na_filter為是否檢查丟失值(空字符串或空值)。對于大文件來說,數(shù)據(jù)集中沒有空值,設定na_filter=False可以提升讀取速度。
- # 布爾型,默認為True
- pd.read_csv(data, na_filter=False) # 不檢查
19 日期時間解析
日期時間解析器參數(shù)date_parser用于解析日期的函數(shù),默認使用dateutil.parser.parser來做轉(zhuǎn)換。
如果為某些或所有列啟用了parse_dates,并且datetime字符串的格式都相同,則通過設置infer_datetime_format=True,可以大大提高解析速度,pandas將嘗試推斷datetime字符串的格式,然后使用更快的方法解析字符串,從而將解析速度提高5~10倍。如果無法對整列做出正確的推斷解析,Pandas將返回到正常的解析模式。
下面是一些可自動推斷的日期時間字符串示例,它們都表示2020年12月30日00:00:00:
- "20201230"
- "2020/12/30"
- "20201230 00:00:00"
- "12/30/2020 00:00:00"
- "30/Dec/2020 00:00:00"
- "30/December/2020 00:00:00"
- # 解析時間的函數(shù)名,默認為None
- # 指定時間解析庫,默認是dateutil.parser.parser
- date_parser = pd.io.date_converters.parse_date_time
- date_parser = lambda x: pd.to_datetime(x, utc=True, format='%d%b%Y')
- date_parser = lambda d: pd.datetime.strptime(d, '%d%b%Y')
- # 使用
- pd.read_csv(data, parse_dates=['年份'], date_parserdate_parser=date_parser)
parse_dates參數(shù)用于對時間日期進行解析。
- # 布爾型、整型組成的列表、列表組成的列表或者字典,默認為False
- pd.read_csv(data, parse_dates=True) # 自動解析日期時間格式
- pd.read_csv(data, parse_dates=['年份']) # 指定日期時間字段進行解析
- # 將第1、4列合并解析成名為“時間”的時間類型列
- pd.read_csv(data, parse_dates={'時間':[1,4]})
如果infer_datetime_format被設定為True并且parse_dates可用,那么Pandas將嘗試轉(zhuǎn)換為日期類型。
- # 布爾型,默認為False
- pd.read_csv(data, parse_dates=True, infer_datetime_format=True)
如果用上文中的parse_dates參數(shù)將多列合并并解析成一個時間列,設置keep_date_col的值為True時,會保留這些原有的時間組成列;如果設置為False,則不保留這些列。
- # 布爾型,默認為False
- pd.read_csv(data, parse_dates=[[1, 2], [1, 3]], keep_date_col=True)
對于DD/MM格式的日期類型,如日期2020-01-06,如果dayfirst=True,則會轉(zhuǎn)換成2020-06-01。
- # 布爾型,默認為False
- pd.read_csv(data, dayfirst=True, parse_dates=[0])
cache_dates如果為True,則使用唯一的轉(zhuǎn)換日期緩存來應用datetime轉(zhuǎn)換。解析重復的日期字符串,尤其是帶有時區(qū)偏移的日期字符串時,可能會大大提高速度。
- # 布爾型,默認為True
- pd.read_csv(data, cache_dates=False)
20 文件處理
以下是一些對讀取文件對象的處理方法。iterator參數(shù)如果設置為True,則返回一個TextFileReader對象,并可以對它進行迭代,以便逐塊處理文件。
- # 布爾型,默認為False
- pd.read_csv(data, iterator=True)
- chunksize指定文件塊的大小,分塊處理大型CSV文件。
- # 整型,默認為None
- pd.read_csv(data, chunksize=100000)
- # 分塊處理大文件
- df_iterator = pd.read_csv(file, chunksize=50000)
- def process_dataframe(df):
- pass
- return processed_df
- for index,df_tmp in enumerate(df_iterator):
- df_processed = process_dataframe(df_tmp)
- if index > 0:
- df_processed.to_csv(path)
- else:
- df_processed.to_csv(path, mode='a', header=False)
compression(壓縮格式)用于對磁盤數(shù)據(jù)進行即時解壓縮。如果為“infer”,且filepath_or_buffer是以.gz、.bz2、.zip或.xz結(jié)尾的字符串,則使用gzip、bz2、zip或xz,否則不進行解壓縮。如果使用zip,則ZIP文件必須僅包含一個要讀取的數(shù)據(jù)文件。設置為None將不進行解壓縮。
- # 可選值有'infer'、'gzip'、'bz2'、'zip'、'xz'和None,默認為'infer'
- pd.read_csv('sample.tar.gz', compression='gzip')
encoding(編碼)指定字符集類型,通常指定為'utf-8'。
- # 字符型,默認為None
- pd.read_csv('gairuo.csv', encoding='utf8')
- pd.read_csv("gairuo.csv",encoding="gb2312") # 常見中文
21 符號
以下是對文件中的一些數(shù)據(jù)符號進行的特殊識別處理。如下設置千分位分隔符thousands:
- # 字符型,默認為None
- pd.read_csv('test.csv', thousands=',') # 逗號分隔
小數(shù)點decimal,識別為小數(shù)點的字符。
- # 字符串,默認為'.'
- pd.read_csv(data, decimal=",")
行結(jié)束符lineterminator,將文件分成幾行的字符,僅對C解析器有效。
- # 長度為1的字符串,默認為None
- data = 'a,b,c~1,2,3~4,5,6'
- pd.read_csv(StringIO(data), lineterminator='~')
引號quotechar,用于表示引用數(shù)據(jù)的開始和結(jié)束的字符。引用的項目可以包含定界符,它將被忽略。
- # 長度為1的字符串
- pd.read_csv(file, quotechar='"')
在csv模塊中,數(shù)據(jù)可能會用引號等字符包裹起來,quoting參數(shù)用來控制識別字段的引號模式,它可以是Python csv模塊中的csv.QUOTE_*常量,也可以傳入對應的數(shù)字。各個傳入值的意義如下。
- 0或csv.QUOTE_MINIMAL:僅特殊字段有引號。
- 1或csv.QUOTE_ALL:所有字段都有引號。
- 2或csv.QUOTE_NONNUMERIC:所有非數(shù)字字段都有引號。
- 3或csv.QUOTE_NONE:所有字段都沒有引號。
如果使用csv模塊,則需要事先引入csv模塊。
- # 整型或者csv.QUOTE_*實例, 默認為0
- import csv
- pd.read_csv('input_file.csv', quoting=csv.QUOTE_NONE)
雙引號doublequote,當單引號已經(jīng)被定義,并且quoting參數(shù)不是QUOTE_NONE的時候,使用雙引號表示將引號內(nèi)的元素作為一個元素使用。
- # 布爾型,默認為True
- import csv
- pd.read_csv('data.csv', quotechar='"', doublequote=True, quoting=csv.QUOTE_NONNUMERIC)
escapechar可以傳入一個轉(zhuǎn)義符,用于過濾數(shù)據(jù)中的該轉(zhuǎn)入符。比如,如果一行用雙引號包裹著的數(shù)據(jù)中有換行符,用以下代碼可以過濾其中的換行符。
- # 長度為1的轉(zhuǎn)義字符串,默認為None
- pd.read_csv(StringIO(data), escapechar='\n', encoding='utf-8')
注釋標識comment,指示不應分析行的部分。如果在一行的開頭找到該標識,則將完全忽略該行。此參數(shù)必須是單個字符。像空行一樣(只要skip_blank_lines = True),注釋的行將被參數(shù)header忽略,而不是被skiprows忽略。例如,如果comment ='#',則解析header=0的'#empty \ na,b,c \ n1,2,3'會將'a,b,c'視為header。
- # 字符串,默認為None
- s = '# notes\na,b,c\n# more notes\n1,2,3'
- pd.read_csv(StringIO(s), sep=',', comment='#', skiprows=1)
空格分隔符delim_whitespace,指定是否將空格(例如''或'\ t')用作分隔符,等效于設置sep ='\s+'。如果此選項設置為True,則不應該為delimiter參數(shù)傳遞任何內(nèi)容。
- # 布爾型,默認為False
- pd.read_csv(StringIO(data), delim_whitespace=False)
22 小結(jié)
通過本文的介紹,我們了解了讀取CSV文件的一些參數(shù)的功能,也了解了在讀取CSV文件時可以做一些初步的數(shù)據(jù)整理工作。