[解決!Python]CSVファイルから読み込みを行うには(csvモジュール編)解決!Python

pandasやNumpyを使わずに、Pythonに標準で付属するcsvモジュールを使って、CSVファイルから読み込みを行う方法を紹介する。

» 2023年10月04日 05時00分 公開
[かわさきしんじDeep Insider編集部]
「解決!Python」のインデックス

連載目次

* 本稿は2021年08月03日に公開された記事をPython 3.12.0で動作確認したものです(確認日:2023年10月04日)。


# csvモジュールを使ってCSVファイルから1行ずつ読み込む
import csv

filename = 'populationdata.csv'
with open(filename, encoding='utf8', newline='') as f:
    csvreader = csv.reader(f)
    for row in csvreader:
        print(row)
# 出力結果:
#['年', '地域コード', '地域', '総人口']
#['1920年', '00000', '全国', '55963053']
# …… 省略 ……
#['2010年', '00000', '全国', '128057352']
#['2020年', '00000', '全国', '126226568']

# タブ区切りの文字を読み込む
filename = 'tabdelimiteddata.tsv'
with open(filename, encoding='utf8', newline='') as f:
    csvreader = csv.reader(f, delimiter='\t')
    for row in csvreader:
        print(row)  # 出力結果は省略

# CSVファイルの内容を1つのリストにまとめる
filename = 'populationdata.csv'
with open(filename, encoding='utf8', newline='') as f:
    csvreader = csv.reader(f)
    content = [row for row in csvreader]  # 各年のデータを要素とするリスト
    #content = []
    #for row in csvreader:
    #    content.append(row)

print(content)
# 出力結果:
#[['年', '地域コード', '地域', '総人口'], ['1920年', '00000', '全国',
# '55963053'], …… , ['2010年', '00000', '全国', '128057352'], ['2020年',
# '00000', '全国', '126226568']]

# 特定の列のデータ型を変換する
with open(filename, encoding='utf8', newline='') as f:
    csvreader = csv.reader(f)
    header = next(csvreader)  # 見出し行は別扱い
    content = [[row[0], row[1], row[2], int(row[3])] for row in csvreader]

content.insert(0, header)  # 最後にリストの先頭に見出し行を挿入
print(content)
# 出力結果:
#[['年', '地域コード', '地域', '総人口'], ['1920年', '00000', '全国',
# 55963053], …… , ['2010年', '00000', '全国', 128057352], ['2020年',
# '00000', '全国', 126226568]]

# 数値フィールド以外はシングルクオートで囲まれていることを指示して
# 数値フィールドの値を全て浮動小数点数値に自動的に変換
filename = 'sample.csv'
with open(filename, encoding='utf8', newline='') as f:
    csvreader = csv.reader(f, quotechar="'", quoting=csv.QUOTE_NONNUMERIC)
    for row in csvreader:
        print(row) 
# 出力結果
# ['年', '地域コード', '地域', '総人口']
# ['1920年', '00000', '全国', 55963053.0]
# …… 省略 ……
# ['2010年', '00000', '全国', 128057352.0]
# ['2020年', '00000', '全国', 126226568.0]

# CSVファイルの内容から辞書形式のデータを作成
with open(filename, encoding='utf8', newline='') as f:
    csvreader = csv.DictReader(f)
    content = [row for row in csvreader]

print(content[0])
# 出力結果:
#{'年': '1920年', '地域コード': '00000', '地域': '全国', '総人口': '55963053'}


 本稿では、サンプルのCSVファイルの内容として以下を利用する。1行目は見出し行であり、各行には各年/地域コード/地域/総人口の4つのデータが含まれている。

年,地域コード,地域,総人口
1920年,00000,全国,55963053
1930年,00000,全国,64450005
1940年,00000,全国,73075071
1950年,00000,全国,84114574
1960年,00000,全国,94301623
1970年,00000,全国,104665171
1980年,00000,全国,117060396
1990年,00000,全国,123611167
2000年,00000,全国,126925843
2010年,00000,全国,128057352
2020年,00000,全国,126226568


出典:政府統計の総合窓口(e-Stat)
上記サイトの時系列表から得られる総人口のデータを加工して利用しています。


csvモジュールを使ったCSVファイルの読み込み

 Pythonにはcsvモジュールが標準で添付されている。これをインポートすることで、CSVファイルの読み込みが行える(ただし、CSVファイルの読み込みをより柔軟な形で行うのであれば、pandasNumpyを使った方がよいだろう)。

 その基本的な手順は次の通り。

  1. CSVファイルを表すファイルオブジェクトを作成
  2. そのファイルオブジェクトを、csv.reader関数に渡して、readerオブジェクトを取得
  3. readerオブジェクトは反復処理可能なので、for文や内包表記などを使って、CSVファイルの内容を読み込む

 実際の例を以下に示す。

import csv

filename = 'populationdata.csv'
with open(filename, encoding='utf8', newline='') as f:
    csvreader = csv.reader(f)
    for row in csvreader:
        print(row)
# 出力結果:
#['年', '地域コード', '地域', '総人口']
#['1920年', '00000', '全国', '55963053']
# …… 省略 ……
#['2010年', '00000', '全国', '128057352']
#['2020年', '00000', '全国', '126226568']


 この例では、open関数で本稿冒頭に示したサンプルのCSVファイルをオープンし、そのファイルオブジェクトをcsv.reader関数に渡してreaderオブジェクトを取得している。その後は、for文に反復可能オブジェクトとしてreaderオブジェクトを渡して、CSVから1行ずつ読み込みを行い、各行の内容を表示しているだけだ。

 なお、open関数のnewline引数には空文字列を渡しているが、これは行末コードの変換を行わないことを意味している。これは、CSVファイルのフィールド要素に改行が含まれている場合に、それらを適切に解釈するために推奨されている。

 カンマ「,」ではなく、タブ文字でフィールドが区切られている場合には、csv.reader関数のdelimiter引数に'\t'を渡せば、タブ区切りのファイルからの読み込みも可能だ。

filename = 'tabdelimiteddata.tsv'
with open(filename, encoding='utf8', newline='') as f:
    csvreader = csv.reader(f, delimiter='\t')
    for row in csvreader:
        print(row)  # 出力結果は省略


内包表記を使って、CSVファイルの内容を1つのリストに読み込む

 CSVから1行ずつ読み込みを行って、逐次的に処理を行うのではなく、CSVファイルの内容を1つのオブジェクトとして読み込んでしまうのであれば、リスト内包表記を使ってリストのリストを作成するのが簡単だ。

 以下に例を示す。

filename = 'populationdata.csv'
with open(filename, encoding='utf8', newline='') as f:
    csvreader = csv.reader(f)
    content = [row for row in csvreader]  # 各年のデータを要素とするリスト
    #content = []
    #for row in csvreader:
    #    content.append(row)

print(content)
# 出力結果:
#[['年', '地域コード', '地域', '総人口'], ['1920年', '00000', '全国',
# '55963053'], …… , ['2010年', '00000', '全国', '128057352'], ['2020年',
# '00000', '全国', '126226568']]


 この例では、open関数を呼び出して得たファイルオブジェクトからreaderオブジェクトを作成したら、内包表記を使って、各行の内容(年/地域コード/地域/総人口)を要素とするリストを作成している(コメントアウトしてあるのは、同様な処理をfor文で書いたものだ)。

フィールドの型を変換する

 CSVファイルから読み込んだ内容は通常、全て文字列値となる。そのため、整数値や浮動小数点数値に変換する必要があれば、以下のように内包表記の内部で型変換をするとよい。

 例えば、サンプルのCSVファイルでは各行には年/地域コード/地域/総人口の4つのデータが含まれている。最初の3つは文字列が適切だが、最後の総人口は整数値となっていた方が扱いやすいだろう。そこで、以下のようにして最後のフィールドだけ整数値に変換を行える。

filename = 'populationdata.csv'
with open(filename, encoding='utf8', newline='') as f:
    csvreader = csv.reader(f)
    header = next(csvreader)  # 見出し行は特別扱い
    content = [[row[0], row[1], row[2], int(row[3])] for row in csvreader]

content.insert(0, header)  # 最後にリストの先頭に見出し行を挿入
print(content)
# 出力結果:
#[['年', '地域コード', '地域', '総人口'], ['1920年', '00000', '全国',
# 55963053], …… , ['2010年', '00000', '全国', 128057352], ['2020年',
# '00000', '全国', 126226568]]


 この例では、最後のフィールドだけint関数で総人口を整数値に変換している。このとき見出し行には数値データが含まれていないので、特別扱いするのを忘れないようにしよう。

 また、CSVファイルのフォーマットによるが、数値以外のデータは全て引用符で囲まれているといった場合には、quotingキーワード引数にcsv.QUOTE_NONNUMERICを指定することで、引用符に囲まれていないデータを全て浮動小数点数値に変換させることも可能だ。以下に例を示す。

filename = 'sample.csv'
with open(filename, encoding='utf8', newline='') as f:
    csvreader = csv.reader(f, quotechar="'", quoting=csv.QUOTE_NONNUMERIC)
    for row in csvreader:
        print(row)
# 出力結果
# ['年', '地域コード', '地域', '総人口']
# ['1920年', '00000', '全国', 55963053.0]
# …… 省略 ……
# ['2010年', '00000', '全国', 128057352.0]
# ['2020年', '00000', '全国', 126226568.0]


 ここではquoting引数にquoting=csv.QUOTE_NONNUMERICを指定して数値データ以外のフィールドは全て引用符で囲まれていることと、quotechar引数に"'"を指定してそれらのフィールドはシングルクオートで囲まれていることを指示している。最後のフィールドの値が浮動小数点数値になっている点に注目されたい。

CSVファイルの内容から辞書形式のデータを作成

 各行について、列名とその列のデータの組から成るデータを作成したいのであれば、csv.DictReaderクラスを使用する。csv.reader関数と同じように、csv.DictReaderクラスのコンストラクタ呼び出しにファイルオブジェクトを渡し、csv.DictReaderオブジェクトを得たら、それを使って反復処理を行うだけだ。

 以下に例を示す。

filename = 'populationdata.csv'
with open(filename, encoding='utf8', newline='') as f:
    csvreader = csv.DictReader(f)
    content = [row for row in csvreader]

print(content[0])
# 出力結果:
#{'年': '1920年', '地域コード': '00000', '地域': '全国', '総人口': '55963053'}


 ここで使用しているサンプルのCSVファイルでは1行目が見出し行となっている。そのため、csv.DictReader呼び出しにはファイルオブジェクトだけを渡している。このときには、1行目がフィールド名として解釈される。最初の要素の出力を見ると、「{'年': '1920年', '地域コード': '00000', '地域': '全国', '総人口': '55963053'}」のように辞書になっていることが確認できる。

 CSVファイルに見出し行がないときには、以下のように、fieldnames引数に見出しを渡す。

filename = 'noheader.csv'
with open(filename, encoding='utf8', newline='') as f:
    fieldnames = ['年','地域コード','地域','総人口']
    csvreader = csv.DictReader(f, fieldnames=fieldnames)
    for row in csvreader:
        print(row)


「解決!Python」のインデックス

解決!Python

Copyright© Digital Advantage Corp. All Rights Reserved.

RSSについて

アイティメディアIDについて

メールマガジン登録

@ITのメールマガジンは、 もちろん、すべて無料です。ぜひメールマガジンをご購読ください。