【Python】CSVファイル読み込み時のヘッダー(列名)有り無し処理について

Generic placeholder image

投稿日2020年8月10日 / 更新日2020年8月10日


今回はPython標準ライブラリのcsvモジュールを使用して、CSVファイルの読み込みや書き込み、そしてファイル内のデータを取得していきたいと思います。

題名にもあるようにheader(ヘッダー)が有り無しかでデータの取得も困難になると思われるので、それらの回避方法やヘッダーを利用したデータの取得方法を紹介していこうと思います。

【目次】

実行環境

実行環境
Windows Subsystem for Linux Ubuntu
Python 3.6.9

基本的な処理

まずはCSVファイルへ書き込むために、データを準備します。


access_log = [
        ['日付', 'アクセス数'],  # ヘッダー有り
        ['2020-08-04', 100],  # ここから要素
        ['2020-08-05', 110],
        ['2020-08-06', 90],
        ['2020-08-07', 80],
        ['2020-08-08', 50],
]

1列目に日付の入ったデータ、2列目にアクセス数の入ったデータをリストのリストとして変数に格納しました。

殆どの場合がヘッダーにその列の名前が記されたCSVファイル、もしくわEXCELファイルになると思います。

CSVへ書き込み

先ほど準備した「access_log」をCSVファイルへ書き込みます。


import csv

with open('access_log.csv', 'wt') as f:
    csvout = csv.writer(f)
    csvout.writerows(access_log)

access_log.csvというファイルが作業ディレクトリに有ればちゃんと作成されています。

では書き込んだaccess_log.csvファイルを読み込んでみます。


import csv

with open('access_log.csv', 'rt') as f:
    reader = csv.reader(f)
    access_log_data = [row for row in reader]  # リスト内包表記

print(access_log_data)
[['日付', 'アクセス数'], ['2020-08-04', '100'], ['2020-08-05', '110'], ['2020-08-06', '90'], ['2020-08-07', '80'], ['2020-08-08', '50']]

となります。

では細かい処理について見ていきます。

読み込み時ヘッダー有りCSVファイルの要素の取得

先ほど作成したaccess_log.csvを使用していきますが、例えばそのCSVファイルを読み込んでファイル内の要素を1つずつ取り出して行くとします。


import csv

with open('access_log.csv', 'rt') as f:
    reader = csv.reader(f)
    access_log = [row for row in reader]

# for文を使って要素を1つずつ取り出します
for row in access_log:
    print(row[0])
    print(row[1])
日付
アクセス数
2020-08-04
100
2020-08-05
110
2020-08-06
90
2020-08-07
80
2020-08-08
50

するとヘッダーの部分(列名)まで取り出してしまい少し扱い難くなります。

幾つかの方法を使ってヘッダー以外の要素を取得できるように回避していきます。

OrderDict形式でCSVファイルを読み込む

OrderDictというのは、簡単に言ってしまえば辞書形式の構造ですが「順番が保持」された辞書形式です。

csvモジュールを使用して簡単に読み込むことができます。


import csv

with open('access_log.csv', 'rt') as f:
    dict_reader = csv.DictReader(f)
    access_log = [row for row in dict_reader]

for row in access_log:
    print(row['日付'])
    print(row['アクセス数'])
2020-08-04
100
2020-08-05
110
2020-08-06
90
2020-08-07
80
2020-08-08
50

ヘッダーをキーとしてそれ以外の要素が割り当てられるので、キーを指定する事でその要素を取り出すことができます。

ヘッダーだけスキップして読み込む

CSVファイルの読み込み時に「next()」という関数を加えると、ヘッダーを飛ばして2行目の要素から読み込むことができます。


import csv

with open('access_log.csv', 'rt') as f:
    header = next(csv.reader(f))
    reader = csv.reader(f)
    access_log = [row for row in reader]

for row in access_log:
    print(row[0])
    print(row[1])
2020-08-04
100
2020-08-05
110
2020-08-06
90
2020-08-07
80
2020-08-08
50

綺麗に取得することができました。

ヘッダー(1行目)だけを削除

ヘッダー(1行目)、つまりリスト内の0番目のリストを削除して要素を取得します。

オフセット(スライス)を使用する削除、または要素を明示的に指定して削除する2つの方法を実装します。

極めてシンプルです。

オフセットによるリスト内のリストを削除


import csv

with open('access_log.csv', 'rt') as f:
    reader = csv.reader(f)
    access_log = [row for row in reader]

del access_log[0]  # 1行目を削除

for row in access_log:
    print(row[0])
    print(row[1])
2020-08-04
100
2020-08-05
110
2020-08-06
90
2020-08-07
80
2020-08-08
50

リスト内のリストを明示的に指定して削除


import csv

with open('access_log.csv', 'rt') as f:
    reader = csv.reader(f)
    access_log = [row for row in reader]

access_log.remove(['日付', 'アクセス数'])

for row in access_log:
    print(row[0])
    print(row[1])
2020-08-04
100
2020-08-05
110
2020-08-06
90
2020-08-07
80
2020-08-08
50

読み込み時ヘッダーを設定する

ヘッダー(列名)の無いCSVファイルを読み込む際に、ヘッダーを設定したい場合があると思います。

つまりヘッダー無しのCSVファイルを読み込んだらヘッダー有りになるという設定です。

まずはデータを準備しておきます。


access_log = [
        ['2020-08-04', 100],  # ここから要素
        ['2020-08-05', 110],
        ['2020-08-06', 90],
        ['2020-08-07', 80],
        ['2020-08-08', 50],
]

import csv

with open('access_log.csv', 'wt') as f:
    csvout = csv.writer(f)
    csvout.writerows(access_log)

OrderDict形式で読み込む

先ほども使用しましたが、csvモジュールのDictReader()メソッドの引数にヘッダーを設定することができます。


import csv

with open('access_log.csv', 'rt') as f:
    dict_reader = csv.DictReader(f, fieldnames=['日付', 'アクセス数'])  # 0番目の列からヘッダー名を指定
    access_log = [row for row in dict_reader]

for row in access_log:
    print(row['日付'])
    print(row['アクセス数'])
2020-08-04
100
2020-08-05
110
2020-08-06
90
2020-08-07
80
2020-08-08
50

読み込んだデータにヘッダー(列名)を追加する

普通のcsvモジュールのreader()メソッドで読み込んだ場合は、リスト内にリストが入った状態となります。


import csv

with open('access_log.csv', 'rt') as f:
    reader = csv.reader(f)
    access_log = [row for row in reader]

print(access_log)
[['2020-08-04', '100'], ['2020-08-05', '110'], ['2020-08-06', '90'], ['2020-08-07', '80'], ['2020-08-08', '50']]

このような場合は、Python組み込み関数の「insert()」を使用してリスト内に新しい要素を追加します。


# 0番目にリストを追加(先頭)
access_log.insert(0, ['日付', 'アクセス数'])

print(access_log)
[['日付', 'アクセス数'], ['2020-08-04', '100'], ['2020-08-05', '110'], ['2020-08-06', '90'], ['2020-08-07', '80'], ['2020-08-08', '50']]

要素の取得方法はリスト形式でオフセット(スライス)を使用して取り出すか、辞書形式でキーを指定して取り出すかといった様々な方法がありますが、ほとんどの場合はヘッダー有り(EXCELファイル然り)だと思われるので、ヘッダーの取扱いには慣れた方が良さそうです。

OrderDict形式をCSVファイルとして書き込む

OrderDict形式、つまり辞書型のデータをCSVファイルとして書き込んでいきます。


import csv


# OrderDict形式で読み込む
with open('access_log.csv', 'rt') as f:
    dict_reader = csv.DictReader(f, fieldnames=['日付', 'アクセス数'])
    access_log = [row for row in dict_reader]

print(access_log)
[OrderedDict([('日付', '2020-08-04'), ('アクセス数', '100')]), OrderedDict([('日付', '2020-08-05'), ('アクセス数', '110')]), OrderedDict([('日付', '2020-08-06'), ('アクセス数', '90')]), OrderedDict([('日付', '2020-08-07'), ('アクセス数', '80')]), OrderedDict([('日付', '2020-08-08'), ('アクセス数', '50')])]

import csv

# OrderDict形式のデータを書き込む
with open('access_log.csv', 'wt') as f:
    csvout = csv.DictWriter(f, ['日付', 'アクセス数'])
    csvout.writeheader()
    csvout.writerows(access_log)


with open('access_log.csv', 'rt') as f:
    reader = csv.reader(f)
    access_log = [row for row in reader]

access_log
[['日付', 'アクセス数'],
 ['2020-08-04', '100'],
 ['2020-08-05', '110'],
 ['2020-08-06', '90'],
 ['2020-08-07', '80'],
 ['2020-08-08', '50']]

辞書形式のデータを書き込む際は、csvモジュールのDictWriter()メソッドを使い辞書形式であるデータとして書き込む必要があります。

もしも辞書形式のデータを通常のリスト形式として書き込んでしまった場合は、キーのみ書き込まれて保存されます。

失敗例


import csv


with open('access_log.csv', 'wt') as f:
    csvout = csv.writer(f)
    csvout.writerows(access_log)

with open('access_log.csv', 'rt') as f:
    reader = csv.reader(f)
    access_log = [row for row in reader]

access_log
[['日付', 'アクセス数'],
 ['日付', 'アクセス数'],
 ['日付', 'アクセス数'],
 ['日付', 'アクセス数'],
 ['日付', 'アクセス数']]

辞書構造のデータをCSVファイルとして書き込む

以下のような辞書型のデータがあったとします。


access_dict = {
        '日付': '2020-08-04',
        'アクセス数': 100,
}

print(access_dict)
{'日付': '2020-08-04', 'アクセス数': 100}

このままCSVファイルとして保存を行うとキーである「日付・アクセス数」だけをカンマ区切りで保存してしまいます。

イメージとしては「'日', '付', 'ア', 'ク', 'セ', 'ス', '数',」desu。

そうならない為に辞書データをリストで囲みます。


access_dict = [access_dict]
print(access_dict)
[{'日付': '2020-08-04', 'アクセス数': 100}]

そして辞書型に特化したcsvモジュールのDictWriter()メソッドを使用して書き込みます。


import csv

with open('access_dict.csv', 'wt') as f:
    csvout = csv.DictWriter(f, ['日付', 'アクセス数']) # キーを指定
    csvout.writeheader()
    csvout.writerows(access_dict)

読み込んでみると、上手く保存されていたことが分かります。


import csv

with open('access_dict.csv', 'rt') as f:
    reader = csv.reader(f)
    access_dict = [row for row in reader]

print(access_dict)
[['日付', 'アクセス数'], ['2020-08-04', '100']]

CSVファイルはサンプルデータなどで多く扱われているので、様々な操作方法に慣れていると便利です。

pandasなどの高機能なデータ分析用ライブラリもありますが、簡単な処理を実行する場合は標準で手軽なPythonパッケージを使ってシンプルに終えたいですね。

それでは以上となります。

最後までご覧いただきありがとうございました。


トップページに戻る