ファイルを開く
ここでは “State Population Totals: 2010-2019” のページでダウンロードできる米国の国勢調査のデータを例にする(オリジナルを少し加工している)。
※ 米国国勢調査のデータ ➡ nst-est2019-01
,Census,Estimates Base,2010,2011,2012,2013,2014,2015,2016,2017,2018,2019 United States,"308,745,538","308,758,105","309,321,666","311,556,874","313,830,990","315,993,715","318,301,008","320,635,163","322,941,311","324,985,539","326,687,501","328,239,523" (中略) .Wyoming,"563,626","563,775","564,487","567,299","576,305","582,122","582,531","585,613","584,215","578,931","577,601","578,759" ,,,,,,,,,,,, Puerto Rico,"3,725,789","3,726,157","3,721,525","3,678,732","3,634,488","3,593,077","3,534,874","3,473,232","3,406,672","3,325,286","3,193,354","3,193,694"
csvファイルはカンマで値を区切ってある形式で、カンマを含む数値は文字列として保存されている。csvファイルはopen()
関数によって普通のファイルとして開くことができる。
for line in open('nst-est2019-01.csv', 'r').readlines(): choped_line = line[:-1] print(choped_line)
このように普通のファイルとして開くことができるが、csv形式のファイルを簡便に扱うにはcsvモジュールを使うのがよい。
import csv with open('nst-est2019-01.csv', 'r') as f: reader = csv.reader(f) for line in reader: print(line)
csv.reader()
で読み込むと各行について各列の成分を要素とするリストを返す。
pandasでcsvを読み込む
一般に、csvファイルを使ってデータのチェックを行う際はしばしば大量のデータを取り扱うことになる。そのような場合に有用なのがpandasライブラリである。pandasにはデータ分析を支援する様々なモジュールが搭載されており、csvファイルの取扱いもpandasが得意とするところの一つである。
(参考:pandasの公式ユーザーガイド)
import pandas as pd df = pd.read_csv('nst-est2019-01.csv', header=0) print(df)
このコードの実行結果は以下のようになる。pandasのread_csv
関数でcsvファイルを読み込むと一番左の列に行番号が付け足される。
Unnamed: 0 Census ... 2018 2019 0 United States 308,745,538 ... 326,687,501 328,239,523 1 Northeast 55,317,240 ... 56,046,620 55,982,803 2 Midwest 66,927,001 ... 68,236,628 68,329,004 3 South 114,555,744 ... 124,569,433 125,580,448 (中略) 55 .Wyoming 563,626 ... 577,601 578,759 56 NaN NaN ... NaN NaN 57 Puerto Rico 3,725,789 ... 3,193,354 3,193,694 [58 rows x 13 columns]
read_csv
の引数にheader=0
を指定しているが、0がデフォルト設定なので、このデータの場合は省略しても問題無い。例えばheader=2
とすれば3行目をヘッダー行と見なしてデータが取り込まれる。行番号は0始まりなので注意。
また、空文字列''
や'NaN'
、null
といった文字列は、read_csv()やread_table()では欠損値「NaN
」として扱われる。open()関数と同様に、ファイルのエンコード方式に合わせてencoding='shift_jis'
などと指定することもできる。
数字の3桁区切りの対処法
統計データや会計データなどの大きな整数値を扱う場合、要素の整数値が3桁ごとにカンマで区切られていることがある(文字列扱いになっている)。このような場合はread_csv関数の引数にthousands=','
を付けて読み込めばよい。
import pandas as pd df = pd.read_csv('nst-est2019-01.csv', thousands=',') print(df) # Unnamed: 0 Census ... 2018 2019 # 0 United States 308745538.0 ... 326687501.0 328239523.0 # 1 Northeast 55317240.0 ... 56046620.0 55982803.0 # 2 Midwest 66927001.0 ... 68236628.0 68329004.0 # (以下略)
これにより、普通は文字列として読み込まれる数字が、数値として扱えるようになる(ただし整数ではなく浮動小数点数扱い)。
3桁区切りを取り払うことで、例えばmatplotlibを使って人口統計データを可視化することができる。
import matplotlib.pyplot as plt import pandas as pd df = pd.read_csv('nst-est2019-01.csv', thousands=',').dropna(how='all') plt.bar([ i for i in range(52)], df['Census'].loc[5:]) plt.show()
dropna(how='all')
で空の行をスキップして読み込んでいる。また、df['Census'].loc[5:]
で ‘Census’ というラベルの列データについて5行目以降を抽出している。[ i for i in range(52)]
は0から51までの52個の整数リスト(iterableオブジェクト)を生成するリスト内包表記である。
なお、アメリカの州は50州だが、この統計データはコロンビア特別区(District of Columbia)とプエルトリコ(Puerto Rico)を別枠にしているので、上の棒グラフでは52エントリになっている。
csvへの書き込み
csvファイルへ書き込みするには、まずcsv.writer()
クラスでオブジェクトを生成し、writerow()
関数を使って各行にリストを出力する。例えば以下のコードは九九表を「Multiplication.csv」という名前で生成する。
import csv with open('Multiplication.csv', 'w') as f: w = csv.writer(f) for i in range(10): w.writerow([(i+1)*(j+1) for j in range(10)])
pandasで読み込むことが想定される場合にはヘッダー行だけ別に出力しておく。
区切り文字の指定
区切り文字(delimiter;デリミタ)はデフォルトだとカンマだが、csv.writerの引数にdelimiterを指定することで変更することができる。例えば以下のようにすればタブ区切りを指定できる。
import csv with open('Multiplication.csv', 'w') as f: w = csv.writer(f, delimiter='\t') for i in range(10): w.writerow([(i+1)*(j+1) for j in range(10)])
要素を引用符で囲む
csv.writerの引数に quoting=csv.QUOTE_ALL と指定すれば、すべての要素が引用符で囲まれる。
import csv with open('Multiplication.csv', 'w') as f: w = csv.writer(f, quoting=csv.QUOTE_ALL) for i in range(10): w.writerow([(i+1)*(j+1) for j in range(10)])
quoting=csv.QUOTE_NONNUMERIC と指定すれば数値以外の要素が引用符で囲まれる。
また、quoting=csv.QUOTE_NONE と指定すればすべての要素が引用符で囲まれなくなる。ただしQUOTE_NONEを使う場合は、以下のように引数 escapechar によりエスケープに使う文字を指定する必要がある(要素内のカンマと要素間のカンマを識別するため)。
import csv header = ["","Census","Estimates Base","2010","2011","2012","2013","2014","2015","2016","2017","2018","2019"] usa = ["United States","308,745,538","308,758,105","309,321,666","311,556,874","313,830,990","315,993,715","318,301,008","320,635,163","322,941,311","324,985,539","326,687,501","328,239,523"] with open('usa.csv', 'w') as f: w = csv.writer(f, quoting=csv.QUOTE_NONE, escapechar='\\') w.writerow(header) w.writerow(usa) # ,Census,Estimates Base,2010,2011,2012,2013,2014,2015,2016,2017,2018,2019 # United States,308\,745\,538,308\,758\,105,309\,321\,666,311\,556\,874,313\,830\,990,315\,993\,715,318\,301\,008,320\,635\,163,322\,941\,311,324\,985\,539,326\,687\,501,328\,239\,523