Pythonでcsv読み込み numpyで配列を入力・出力

PythonのCSV 読み込み/csv.reader

PythonのCSV 読み込み/csv.reader

 

pythonのcsv読み込み 列を指定

テスト用のCSVファイルとして、統計センターの基本素材(47都道府県の基本データ)をダウンロードし、nkfコマンドでUTF-8に変換しました。

# csvファイルの文字コードを確認
$ nkf -g SSDSE-E-2022v2.csv
Shift_JIS
# UTF-8に変換
$ nkf -w --overwrite SSDSE-E-2022v2.csv
# csvファイルの文字コードを確認
$ nkf -g SSDSE-E-2022v2.csv
UTF-8

CSVファイルの先頭付近を見てみると、以下のようになっています。

「都道府県」の列を指定して読み込んでみましょう。csv読み込みには、標準ライブラリのcsvモジュールのreader(csv.reader)を使用します。

csv.readerを使うメリットは、標準ライブラリなので追加インストールが不要、という点。

$ cat csv_readsample1.py
#!/usr/bin/python3

import csv

file1='SSDSE-E-2022v2.csv'

with open(file1, newline='') as csvfile:
myreader=csv.reader(csvfile, delimiter=',')
for row in myreader:
print( row[0], row[1] )

CSVファイルの0列目と1列目を表示します。rowに1行のデータがまるごと入っているので、配列番号で0列目と1列目を指定しています。実行するとこうなります。

$ ./csv_readsample1.py
SSDSE-E-2022v2 prefecture
年度
地域コード 都道府県
R00000 全国
R01000 北海道
R02000 青森県
R03000 岩手県
R04000 宮城県
R05000 秋田県
R06000 山形県
  : 
  :

行指定でcsvの読み込み

都道府県のデータは、5行目から始まっているようです。5行目以降と指定して読み込みを行ってみましょう。

csv.reader自体には行指定の機能がありません。サンプルでは、読み飛ばしたい回数だけ、ダミーの空読み処理を4回おこなうことで、5行目以降から読み込みを開始するようにしています。

$ cat csv_readsample2.py
#!/usr/bin/python3

import csv

file1='SSDSE-E-2022v2.csv'

with open(file1, newline='') as csvfile:
myreader=csv.reader(csvfile, delimiter=',')

dummy=next(myreader)
dummy=next(myreader)
dummy=next(myreader)
dummy=next(myreader)

for row in myreader:
print( row[0], row[1] )

実行するとこうなります。不要な行が読み飛ばされ、実際のデータのみを取得できました。

$ ./csv_readsample2.py
R01000 北海道
R02000 青森県
R03000 岩手県
R04000 宮城県
R05000 秋田県
R06000 山形県
  :
  :

行指定などの制御を、もっと凝った形でおこないたい場合は、pandasに読み込む関数を使用したほうが良いかも知れません。(当記事の下の方で解説)

csvをリストに読み込み

csvをリストに読み込むには、1行づつcsvファイルを読み込むforループ内で、空のリスト型オブジェクトにappendをおこないます。

以下のコードは、csvファイルの5行目以降から「都道府県コード」「都道府県名」を読み込んで、リストに追加し、リストの内容を表示するサンプルです。

$ cat ./csv_readsample3.py
#!/usr/bin/python3

import csv

file1='SSDSE-E-2022v2.csv'

with open(file1, newline='') as csvfile:
myreader=csv.reader(csvfile, delimiter=',')

dummy=next(myreader)
dummy=next(myreader)
dummy=next(myreader)
dummy=next(myreader)

mylist=[]

for row in myreader:
mylist.append([row[0],row[1]])

print( mylist )

実行するとこうなります。

$ ./csv_readsample3.py
[['R01000', '北海道'], ['R02000', '青森県'], ['R03000', '岩手県'], ['R04000', '宮城県'], ['R05000', '秋田県'], ['R06000', '山形県'], ['R07000', '福島県'], ['R08000', '茨城県'], ['R09000', '栃木県'], ['R10000', '群馬県'], ['R11000', '埼玉県'], ['R12000', '千葉県'], ['R13000', '東京都'],…

指定の列だけでなく、全ての列をリストに読み込むには、リストに追加(append)している部分を以下のようにします。(赤字の部分)

$ cat csv_readsample4.py
#!/usr/bin/python3

import csv

file1='SSDSE-E-2022v2.csv'

with open(file1, newline='') as csvfile:
myreader=csv.reader(csvfile, delimiter=',')

dummy=next(myreader)
dummy=next(myreader)

mylist=[]

for row in myreader:
 mylist.append(row)

print( mylist )

ダミー読み込みを4回から2回にしているのは、3行目のラベルのみの行、4行目の「全国」を取り込みたいため。実行するとこうなります。

$ ./csv_readsample4.py
[['地域コード', '都道府県', '総人口', '日本人人口', '15歳未満人口', '15~64
人口', '65歳以上人口', '外国人人口', '出生数', '合計特殊出生率', '死亡数', '
入者数(日本人移動者)', '転出者数(日本人移動者)', '一般世帯数', '一般世帯
員数', '単独世帯数', '婚姻件数', '離婚件数', '総面積(北方地域及び竹島を除く
', '可住地面積', '自然公園面積', '県内総生産額(平成23年基準)', '県民所得(
成23年基準)', '1人当たり県民所得(平成23年基準)', '事業所数(民営)', '事業
所数(民営)(建設業)', '事業所数(民営)(製造業)', '事業所数(民営)(情
通信業)', '事業所数(民営)(卸売業,小売業)', '事業所数(民営)(宿泊業,
食サービス業)', '事業所数(民営)(生活関連サービス業,娯楽業)', '事業所数
民営)(医療,福祉)', '従業者数(民営)', '従業者数(民営)(建設業)', '従
者数(民営)(製造業)', '従業者数(民営)(情報通信業)', '従業者数(民営)
卸売業,小売業)', '従業者数(民営)(宿泊業,飲食サービス業)', '従業者数(
 :
 :

リスト型の2次元配列に、csvファイルの内容が読み込まれました。

csvを辞書型に読み込み

csvを辞書型に読み込むには、以下のようにします。

以下のサンプルでは、都道府県コードをキー、都道府県名を値として辞書型オブジェクトに読み込んでいます。

$ cat csv_readsample3.py
#!/usr/bin/python3

import csv

file1='SSDSE-E-2022v2.csv'

with open(file1, newline='') as csvfile:
myreader=csv.reader(csvfile, delimiter=',')

# 不要な2行を読み飛ばし
dummy=next(myreader)
dummy=next(myreader)
# ラベル行を読み飛ばし
dummy=next(myreader)

mydic=dict()

# row[0] 都道府県コード row[1] 都道府県名
for row in myreader:
mydic[row[0]]=row[1]

print( mydic )

実行するとこうなります。

$ ./csv_readsample3.py
{'R00000': '全国', 'R01000': '北海道', 'R02000': '青森県', 'R03000': '岩手県', 'R04000': '宮城県', 'R05000': '秋田県',…

PythonのCSV出力

CSVを読み込んだ後、値を一部更新して、またcsvとして出力したい場合は、csv.writerを使います。

以下は、csvファイルを読み込んで、先頭2行のみスキップして、同じ内容をcsvファイルに出力する例です。

$ cat csv_readsample5.py
#!/usr/bin/python3

import csv

file1='SSDSE-E-2022v2.csv'

with open(file1, newline='') as csvfile:
myreader=csv.reader(csvfile, delimiter=',')

# 先頭2行をスキップ
dummy=next(myreader)
dummy=next(myreader)

mylist=[]

# 先頭2行以外をmylistに読み込み
for row in myreader:
mylist.append(row)

# csvファイルに出力
file1='output.csv'

with open(file1, 'w', newline='') as fp:
 writer=csv.writer(fp, quoting=csv.QUOTE_ALL, delimiter=',')
 writer.writerows( mylist )

csv.writerの引数で、quotingにcsv.QUOTE_ALLを指定し、全ての値を引用符で囲む設定にしています。

実行すると、output.csvファイルが生成されます。output.csvファイルの内容は以下のようになります。

数値まで引用符で囲まれてしまっていますね…。quoting=csv.QUOTE_MINIMALに指定すれば、必要な箇所のみ引用符で囲む(クォ―ティング)するようになります。

Pandasにcsv読み込み(Python)

Pandasにcsv読み込み(Python)

pandasのcsv読み込み

実は、csvファイルの扱いは、csv.readerを使うよりもpandasを使ったほうがかなり簡単。

Pandasを使うメリットは、コードがとてもシンプルで簡単になる点。というか、csvを扱うならpandas一択でいいんじゃない?という気もします。

$ cat csv_pandassample1.py
#!/usr/bin/python3

# pandasはpdという別名でインポートすることが多い。慣習?
import pandas as pd

file1='SSDSE-E-2022v2.csv'

# dfはデータフレームの略。csvの扱いに最適な2次元配列
df=pd.read_csv(file1)

print( df )

これだけで読み込みができてしまいます。実行するとこう。1行に表示できるように、いい感じで中略しつつ表示されます。

$ ./csv_pandassample1.py
SSDSE-E-2022v2 prefecture ... L322102 L322109
0 NaN 年度 ... 2020 2020
1 地域コード 都道府県 ... 住居費(二人以上の世帯) 教養娯 楽費(二人以上の世帯)
2 R00000 全国 ... 17365 24285
3 R01000 北海道 ... 27305 26539
4 R02000 青森県 ... 18537 18924
5 R03000 岩手県 ... 24850 20179
6 R04000 宮城県 ... 24121 22245
7 R05000 秋田県 ... 14661 22769
 :
 :
47 R45000 宮崎県 ... 16200 22878
48 R46000 鹿児島県 ... 20650 22061
49 R47000 沖縄県 ... 22333 14661

[50 rows x 92 columns]

0行目にNaNが出てますね。

関連)PythonのNan判定

不要な先頭2行を読み飛ばすには、read_csvにオプションskiprowsを指定します。

$ cat csv_pandassample2.py
#!/usr/bin/python3

# pandasはpdという別名でインポートすることが多い。慣習?
import pandas as pd

file1='SSDSE-E-2022v2.csv'

# dfはデータフレームの略。csvの扱いに最適な2次元配列
df=pd.read_csv(file1, skiprows=[0,1])

print( df )

実行するとこうなります。

pandasのデータフレームは、行の名前や列の名前などのラベルもデータとして取り込めるんですね。以下の例では、行の名前は単に行番号になっています。データフレームは、データベースやcsvを扱うのに適した、2次元配列の拡張版と言えるでしょう。

$ ./csv_pandassample2.py
地域コード 都道府県 総人口 ... 食料費(二人以上の世帯) 住居 費(二人以上の世帯) 教養娯楽費(二人以上の世帯)
0 R00000 全国 126146099 ... 76440 17365 24285
1 R01000 北海道 5224614 ... 77680 27305 26539
2 R02000 青森県 1237984 ... 75325 18537 18924
3 R03000 岩手県 1210534 ... 74023 24850 20179
 :
 :

Pandasの場合はファイルのオープンとか、リストに読み込むとかのプログラムの処理の流れを考えずに、直感的な操作でcsvファイルを扱うことが出来るんですね。

Pandasでcsv出力する場合は、こうします。

以下は、csvファイルの先頭2行を除いて、別ファイル(output.csv)に出力する例です。

$ cat csv_pandassample3.py
#!/usr/bin/python3

# pandasはpdという別名でインポートすることが多い。慣習?
import pandas as pd

file1='SSDSE-E-2022v2.csv'
file_output='output.csv'

# dfはデータフレームの略。csvの扱いに最適な2次元配列
df=pd.read_csv(file1, skiprows=[0,1])

# dfの内容をfile_outputに出力
df.to_csv(file_output, sep=',', index=False)

実行すると、output.csvを生成します。

デフォルトだと、to_csv()はquoting=0で引用符は最低限つける設定になっています。quoting=1とすれば、全ての要素を引用符で囲むようになります。

df.to_csv(file_output, sep=',', index=False, quoting=1)

なお、0とか1とか後からみてよくわからない数字(マジックナンバー)を使うのがいやだなぁ、という場合は、import csvをおこなって、csv.QUOTE_MINIMAL(=0)やcsv.QUOTE_ALL(=1)などの定数を使うと良いでしょう。

import csv
:
:
(中略)
:
:
df.to_csv(file_output, sep=',', index=False, quoting=csv.QUOTE_MINIMAL)

numpyにcsv読み込み (Python)

numpyにcsv読み込み (Python)

numpyのcsv読み込み

numpyは、標準モジュールのcsv.readerよりも簡潔にコードを書けますが、pandasほどシンプル、簡単ではありません。

numpyでcsvを扱う意味は、計算処理が高速で行える点。

とは言っても、人間が目で見て確認できるサイズのcsvファイルなら、pandasの処理速度と体感的に特に差はありません。機械学習のような多次元配列に膨大なデータを格納するような処理の場合にnumpyを選ぶメリットがあります。

なお、読み込み時間はnumpyよりpandasの方が速いです。

$ cat ./csv_numpysample1.py
#!/usr/bin/python3

# numpyはnpという別名でインポートすることが多い。慣習?
import numpy as np

file1='SSDSE-E-2022v2.csv'

# arはarray(配列)の略。
ar=np.loadtxt(file1, delimiter=',', skiprows=3, dtype='unicode')

print( ar )

loadtxt()では、csvファイル名、区切り文字(delimiter)、読み飛ばし行数(skiprows)、dtype(データタイプ)を指定しています。dtypeは、unicodeを指定しておかないと、日本語が扱えません。

実行するとこうなります。

$ ./csv_numpysample1.py
[['R00000' '全国' '126146099' ... '76440' '17365' '24285']
['R01000' '北海道' '5224614' ... '77680' '27305' '26539']
...
['R45000' '宮崎県' '1069576' ... '71144' '16200' '22878']
['R46000' '鹿児島県' '1588256' ... '70501' '20650' '22061']
['R47000' '沖縄県' '1467480' ... '66197' '22333' '14661']]

dtypeですが、正確にはデフォルトでは「float」型なので、日本語が入ってくると、型のミスマッチを起こすんですね。以下は、loadtxt()にdtype指定をしなかったときに出るエラーです。

$ ./csv_numpysample1.py
Traceback (most recent call last):
File "./csv_numpysample1.py", line 10, in <module>
ar=np.loadtxt(file1, delimiter=',', skiprows=2)
File "/home/kabuki/.local/lib/python3.6/site-packages/numpy/lib/npyio.py", line 1139, in loadtxt
for x in read_data(_loadtxt_chunksize):
File "/home/kabuki/.local/lib/python3.6/site-packages/numpy/lib/npyio.py", line 1067, in read_data
items = [conv(val) for (conv, val) in zip(converters, vals)]
File "/home/kabuki/.local/lib/python3.6/site-packages/numpy/lib/npyio.py", line 1067, in <listcomp>
items = [conv(val) for (conv, val) in zip(converters, vals)]
File "/home/kabuki/.local/lib/python3.6/site-packages/numpy/lib/npyio.py", line 763, in floatconv
return float(x)
ValueError: could not convert string to float: '地域コード'

numpyでcsvファイルを出力するには、savetxt()を使います。以下のサンプルは、csvファイルを先頭2行をスキップして読み込み、output.csvというファイルに出力する例です。

$ more csv_numpysample2.py
#!/usr/bin/python3

# numpyはnpという別名でインポートすることが多い。慣習?
import numpy as np

file1='SSDSE-E-2022v2.csv'
outputfile='output.csv'

# csvファイルを読み込み
# arはarray(配列)の略。
ar=np.loadtxt(file1, delimiter=',', skiprows=2, dtype='unicode')

# csvファイルを出力
np.savetxt( outputfile, ar, fmt='%s', delimiter=',' )

savetxt()で日本語を扱う場合は、フォーマット指定のオプションで、fmt=’%s’を指定する必要があります。numpyはデフォルトでfloat型を想定しているので日本語が入ってくるとエラーになるんですね。

有効桁数をキッチリ指定して、誤差を最小限にしたい場合にはnumpyは有効ですが、カジュアルに日本語を使いたいな―ってときには、numpyめんどくさいかも。

なお、savetxt()でfmt指定をしなかった場合は、以下のエラーが出ます。

$ ./csv_numpysample2.py
Traceback (most recent call last):
File "/home/kabuki/.local/lib/python3.6/site-packages/numpy/lib/npyio.py", line 1424, in savetxt
v = format % tuple(row) + newline
TypeError: must be real number, not numpy.str_

During handling of the above exception, another exception occurred:

実数が入ってくるはずが、文字列がきたんだけど!?みたいなエラー。numpy、めんどくせーやつだな。

でも、float型の膨大な計算を行う機械学習なんかでは、numpyのメリットは相当大きいんですけどね。

Pythonのcsv読み込みまとめ

まとめ

  • 標準モジュールのcsv.readerは、モジュール追加せずに使えるのがメリット
  • Pandasでのcsvの読み書きは一番カンタンでおすすめ。
  • numpyでのcsv読み込みはイマイチだけど、float型の計算が高速なのがメリット