本記事では、PythonでのCSVファイルの扱い方を解説します。機械学習用データや公共機関が提供する統計データはCSVで提供されていることが多いので、扱いに慣れておきましょう。
推奨はpandasライブラリを使用する方法なので、迷ったらこの方法を参考にしてください。
なお、本記事で解説しているソースコードは、以下のGoogle Colabノートブックで実行して動作を確認することができます。ぜひご活用下さい。
CSVは、Comma Separated Valuesの略で、カンマで区切られた値という意味になります。記法は簡単で、名前の通りデータをカンマで区切って並べていく形式です。
例えば、以下の宿泊記録の表データをCSV形式で格納することを考えます。
宿泊日 | 宿泊日数 | 国籍 | 性別 | 年齢 |
---|---|---|---|---|
2022/05/15 | 2 | 日本 | 男性 | 28 |
2022/06/20 | 2 | 日本 | 男性 | 51 |
2022/06/20 | 2 | イギリス | 女性 | 32 |
2022/07/03 | 3 | イギリス | 男性 | 35 |
2022/08/10 | 4 | 日本 | 女性 | 30 |
CSVでは、以下のように書くことが多いです。値をカンマで区切って並べ、表を一行ずつ区切ってCSV側でも同じように改行します。例として、ファイル名をguest.csvとします。
"宿泊日","宿泊日数","国籍","性別","年齢"
"2022/05/15","2","日本","男性","28"
"2022/06/20","2","日本","男性","51"
"2022/06/20","2","イギリス","女性","32"
"2022/07/03","3","イギリス","男性","35"
"2022/08/10","4","日本","女性","30"
1行目に項目名(宿泊日、宿泊日数、…)が、2行目以降に値が並びます。
CSVはシンプルで記法で、様々なプログラミング言語・データベースで直接操作できます。
実務的には、人が1つ1つ処理できない大量のデータを扱うことの方が多いので、データはCSVに格納し、プログラムやデータベースで直接操作する方が都合が良いのです。
Pythonは、Python本体と数値計算ライブラリをパッケージ化したanaconda、anacondaの軽量バージョンであるminicondaなど、様々な形で提供されています。
ただ、2章ではとりあえず最も利用者が多いPython単体(”Vanilla” Pythonと呼ばれます)だけで出来るCSVの扱いを紹介します。
CSVファイルの読み書きのために、csvライブラリをインポートします。pythonでは、ファイルを開く時、open()
メソッドを使用します。open()
の引数にCSVファイルのパスを指定、csv.reader()
にopen()
で読み込んだオブジェクトを指定します。
import csv
with open('guests.csv', 'r') as f:
reader = csv.reader(f)
# 1行ずつ出力
for row in reader:
print(row)
# ['宿泊日','宿泊日数','国籍','性別','年齢']
# ['2022/05/15','2','日本','男性','28']
# ['2022/06/20','2','日本','男性','51']
# ['2022/06/20','2','イギリス','女性','32']
# ['2022/07/03','3','イギリス','男性','35']
# ['2022/08/10','4','日本','女性','30']
CSV形式のデータは、1行ずつ区切られ、Pythonのリストとして格納されます。デフォルトでは、データは全て文字列として認識されるので注意してください。
CSVファイルへの書き込みは、csv.writer()
で行います。また、書き込み時には、open()
に書き込みモード’w”を指定します。
書き込みモードでは、CSVファイルを上書きしてしまうので注意してください。
import csv
with open('guests.csv', 'w') as f:
writer = csv.writer(f)
# CSVファイルに書き込み
writer.writerow(['2022/12/10', '3', 'アメリカ', '女性', '25'])
writer.writerow(['2022/12/10', '3', 'アメリカ', '男性', '30'])
# 書き込み後のCSVファイルの内容を確認
with open('guests.csv', 'r') as f:
reader = csv.reader(f)
for row in reader:
print(row)
# ['2022/12/10', '3', 'アメリカ', '女性', '25']
# ['2022/12/10', '3', 'アメリカ', '男性', '30']
元のCSVファイルを上書きせず、ファイルの後ろに追記したい時は、appendモードを使用します。open()
の引数にappend(追記)を表す’a’を指定します。
# appendモード ' a '
with open('guests.csv', 'a') as f:
writer = csv.writer(f)
# 1行追記
write.writerow(['2022/12/20', '2', '日本', '男性', '50'])
# 書き込み後のCSVファイルの内容を確認
with open('guests.csv', 'r') as f:
reader = csv.reader(f)
for row in reader:
print(row)
# ['宿泊日','宿泊日数','国籍','性別','年齢']
# ['2022/05/15','2','日本','男性','28']
# ['2022/06/20','2','日本','男性','51']
# ['2022/06/20','2','イギリス','女性','32']
# ['2022/07/03','3','イギリス','男性','35']
# ['2022/08/10','4','日本','女性','30']
# ['2022/12/20', '2', '日本', '男性', '50']
CSVファイル全体を、1つの2次元リストにまとめてしまうことも可能です。こうすると、表の行・列を指定する感覚で範囲を指定出来るようになるので便利です。
import csv
with open('guests.csv', 'r') as f:
reader = csv.reader(f)
# CSV全体を2次元リストとして読み込み
data = [row for row in reader]
print(data)
# [['宿泊日','宿泊日数','国籍','性別','年齢'],['2022/05/15','2','日本','男性','28'],['2022/06/20','2','日本','男性','51'],['2022/06/20','2','イギリス','女性','32'],['2022/07/03','3','イギリス','男性','35'],['2022/08/10','4','日本','女性','30']
スライス表記で、行を指定して切り出すことができます。表の行番号・列番号を指定する感覚です。
import csv
with open('guests.csv', 'r') as f:
reader = csv.reader(f)
data = [row for row in reader]
# 1行目から3行名を表示
print(data[0:3])
# [['宿泊日', '宿泊日数', '国籍', '性別', '年齢'], ['2022/05/15', '2', '日本', '男性', '28'], ['2022/06/20', '2', '日本', '男性', '51']]
zip()
関数を使用すれば、行と列をひっくり返す操作(転置を取る)ができます。特定の列だけを取り出すために利用できます。
下の例は、guest.csvの中の、宿泊者の国籍だけを抽出した例です。
import csv
with open('guests.csv', 'r') as f:
reader = csv.reader(f)
data = [row for row in reader]
# zip関数で2次元リストの行と列を入れ替える
data_t = list(zip(*data))
# 元データの3列目(国籍)を出力
print(data_t[2])
# ('国籍', '日本', '日本', 'イギリス', 'イギリス', '日本')
宿泊日 | 宿泊日数 | 国籍 | 性別 | 年齢 |
---|---|---|---|---|
2022/05/15 | 2 | 日本 | 男性 | 28 |
2022/06/20 | 2 | 日本 | 男性 | 51 |
2022/06/20 | 2 | イギリス | 女性 | 32 |
2022/07/03 | 3 | イギリス | 男性 | 35 |
2022/08/10 | 4 | 日本 | 女性 | 30 |
“Vanilla” Pythonでも手軽にCSVが扱えますが、データ分析を行ったり複雑な操作を行ったりする場合にはpandasライブラリの使用を推奨します。
pandasでは、DataFrameという形式でCSVを扱います。試しに、機械学習入門者用のiris(アヤメ)データセットを読み込んで見ましょう。
![](https://navifolio-jp.com/wp-content/uploads/2023/03/iris.webp)
pandasライブラリのread_csv()
メソッドにURLを指定すると、オンラインから直接データを取得可能です。
import pandas as pd
df = pd.read_csv('https://raw.githubusercontent.com/mwaskom/seaborn-data/master/iris.csv')
# データの先頭をいくつか表示
print(df.head())
# sepal_length sepal_width petal_length petal_width species
# 0 5.1 3.5 1.4 0.2 setosa
# 1 4.9 3.0 1.4 0.2 setosa
# 2 4.7 3.2 1.3 0.2 setosa
# 3 4.6 3.1 1.5 0.2 setosa
# 4 5.0 3.6 1.4 0.2 setosa
DataFrameは、以下のような構造で、各行のIDを保存するindex、表のカラム名(項目名)を保存するcolumns、データの中身を持つvaluesの3つで構成されます。
デフォルトの設定では、CSVファイルの1行目がデータのカラム名(項目名)として保存されます。
# カラム名を表示
print(df.columns)
# Index(['sepal_length', 'sepal_width', 'petal_length', 'petal_width','species'],dtype='object')
df.values[]
ではスライス表記で、特定の範囲を指定してデータを抽出することが出来ます。範囲指定の記法は、後述する他のメソッドでも共通なので覚えておきましょう。
# 最初から3行分を出力
print(df.values[:3,:])
# [[5.1 3.5 1.4 0.2 'setosa']
# [4.9 3.0 1.4 0.2 'setosa']
# [4.7 3.2 1.3 0.2 'setosa']]
# 最初から3行分、2列目から4列目を出力
print(df.values[:3, 1:4])
# [[3.5 1.4 0.2]
# [3.0 1.4 0.2]
# [3.2 1.3 0.2]]
同様の操作は、DataFrameのiloc[]
メソッドでも可能です。df.values[]
で抽出したデータはnumpy配列というデータ型に、iloc[]
メソッドの場合はDataFrameのままになります。
# 最初から3行分、2列目から4列目を出力
print(df.iloc[:3, 1:4])
# sepal_width petal_length petal_width
# 0 3.5 1.4 0.2
# 1 3.0 1.4 0.2
# 2 3.2 1.3 0.2
# データ型の表示
print(type(df.values[:3, 1:4]))
# class 'numpy.ndarray'
# print(type(df.iloc[:3, 1:4]))
# class 'pandas.core.frame.DataFrame'
dataFrameのloc[]
メソッドを使用すると、範囲指定にカラム名(項目名)を使用できるため、コードが分かりやすくなる場合があります。
# 最初から3行分の、がく片長さとがく片の幅を出力
print(df.loc[:3, "sepal_length":"sepal_width"])
# sepal_length sepal_width
# 0 5.1 3.5
# 1 4.9 3.0
# 2 4.7 3.2
# 3 4.6 3.1
#全てのデータの花びらの長さだけを抽出
print(df.loc[:, "petal_length":"petal_length"])
# petal_length
# 0 1.4
# 1 1.4
# 2 1.3
# 3 1.5
# 4 1.4
# … …
# 145 5.2
# 146 5.0
# 147 5.2
# 148 5.4
# 149 5.1
DataFrameで使用できるデータの抽出方法について、さらにテクニックを知りたい方は、以下の公式ドキュメントを参考にして下さい。
pandasを推奨する大きな理由の1つとして、平均値・分散などの統計量を簡単に出せることがあります。
前述のirisデータセットを用いて、各品種それぞれの(それぞれ50個体分)花びらの長さの平均値を求めてみましょう。
import pandas as pd
df = pd.read_csv('https://raw.githubusercontent.com/mwaskom/seaborn-data/master/iris.csv')
# 1品種目(setosa)の花びらの長さの平均値
m1 = df.loc[0:50, "petal_length"].mean()
print(m1)
# 1.5254901960784315
# 2品種目(versicolor)の花びらの長さの平均値
m2 = df.loc[50:100, "petal_length"].mean()
print(m2)
# 4.294117647058823
# 3品種目(virginica)の花びらの長さの平均値
m3 = df.loc[100:150, "petal_length"].mean()
print(m3)
# 5.5520000000000005
品種ごとに花びらの長さに違いが見られました。
基本的な統計量に対応するメソッドを下に示します。
統計量 | メソッド |
---|---|
平均値 | .mean() |
分散 | .var() |
標準偏差 | .std() |
最大値 | .max() |
最小値 | .min() |
中央値 | .median() |
最頻値 | .mode() |
データの個数 | .count() |
実践的な統計量の求め方などについて、適宜下記の公式ドキュメントを参照して下さい。
以上で、PythonでのCSVファイルの扱いの説明を終わります。お疲れ様でした。