【Python】csvファイルの処理

PythonのTopに戻る


 

 ファイルを開く

ここでは “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)])

1文字であれば任意の文字を区切り文字に指定可能である。

 

 要素を引用符で囲む

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

 


PythonのTopに戻る