連載
» 2021年09月28日 05時00分 公開

[解決!Python]CSVファイルの読み書きまとめ解決!Python

csvモジュール/NumPy/pandasを使って、CSVファイルを読み書きする方法を1ページにまとめて紹介。

[かわさきしんじ,Deep Insider編集部]

この記事は会員限定です。会員登録(無料)すると全てご覧いただけます。

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

連載目次

csvモジュールを使った読み込み(csv.readerオブジェクト/csv.DictReaderクラス)

# 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ファイルからの読み込みを行う例である。

年,地域コード,地域,総人口
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ファイルからの読み込みについては「CSVファイルから読み込みを行うには(csvモジュール編)」を参照のこと。

csvモジュールを使った書き込み(csv.writerオブジェクトのwriterow/writerowsメソッド、csv.DictWriterクラス)

import csv

# サンプルデータとテキストファイルの内容を出力する関数の準備
header = ['name', 'age', 'tel']
isshiki = ['一色', 25, 'xxxx-yyyy']
endo = ['遠藤', 45, 'mmmm-nnnnn']
kawasaki = ['かわさき', 80, 'zzzz-aaaa']
mylist = [isshiki, endo, kawasaki]

for row in mylist:
    print(row)
# 出力結果:
#['一色', 25, 'xxxx-yyyy']
#['遠藤', 45, 'mmmm-nnnnn']
#['かわさき', 80, 'zzzz-aaaa']

from pathlib import Path
def print_lines():
    print(Path('test.csv').read_text())

# csvモジュールを使って1行の内容をCSVファイルに書き込み
with open('test.csv', 'w', newline='') as f:
    writer = csv.writer(f)
    writer.writerow(isshiki)

print_lines()  # 一色,25,xxxx-yyyy

# csvモジュールを使って複数行の内容をCSVファイルに書き込み
with open('test.csv', 'w', newline='') as f:
    writer = csv.writer(f)
    writer.writerows(mylist)

print_lines()
# 出力結果:
#一色,25,xxxx-yyyy
#遠藤,45,mmmm-nnnnn
#かわさき,80,zzzz-aaaa

# ヘッダーを行頭に書き込む
with open('test.csv', 'w', newline='') as f:
    writer = csv.writer(f)
    writer.writerow(header)
    writer.writerows(mylist)

print_lines()
# 出力結果:
#name,age,tel
#一色,25,xxxx-yyyy
#遠藤,45,mmmm-nnnnn
#かわさき,80,zzzz-aaaa

# 区切り文字をカンマからタブに変更する
with open('test.tsv', 'w', newline='') as f:
    writer = csv.writer(f, delimiter='\t')
    writer.writerow(isshiki)

repr(Path('test.tsv').read_text())  # "'一色\\t25\\txxxx-yyyy\\n'"

# 全てのフィールドを引用符で囲む(デフォルトはダブルクオート)
with open('test.csv', 'w', newline='') as f:
    writer = csv.writer(f, quoting=csv.QUOTE_ALL)
    writer.writerow(isshiki)

print_lines()  # "一色","25","xxxx-yyyy"

# 数値以外のフィールドをシングルクオートで囲む
with open('test.csv', 'w', newline='') as f:
    writer = csv.writer(f, quoting=csv.QUOTE_NONNUMERIC, quotechar="'")
    writer.writerow(isshiki)

print_lines()  # '一色',25,'xxxx-yyyy'

# 辞書の要素をCSVファイルに書き込む
mydict_list = [dict(zip(header, row)) for row in mylist]
for items in mydict_list:
    print(items)
# 出力結果:
#{'name': '一色', 'age': 25, 'tel': 'xxxx-yyyy'}
#{'name': '遠藤', 'age': 45, 'tel': 'mmmm-nnnnn'}
#{'name': 'かわさき', 'age': 80, 'tel': 'zzzz-aaaa'}

with open('test.csv', 'w', newline='') as f:
    writer = csv.DictWriter(f, fieldnames=header)
    writer.writeheader()
    writer.writerows(mydict_list)

print_lines()
# 出力結果:
#name,age,tel
#一色,25,xxxx-yyyy
#遠藤,45,mmmm-nnnnn
#かわさき,80,zzzz-aaaa


 csvモジュールを使ったCSVファイルへの書き込みについては「CSVファイルに書き込みを行うには(csvモジュール編)」を参照のこと。

NumPyを使った読み込み(numpy.loadtxt/np.genfromtxt関数)

import numpy as np
from pathlib import Path

# numpy.loadtxt関数

# 読み込むCSVファイルの内容を確認
filename = 'nptest0.csv'
print(Path(filename).read_text())
#0 1 2  # 数値が空白文字で区切られている
#3 4 5
#6 7 8

# loadtxt関数の基本的な使い方
myarray = np.loadtxt(filename)  # デフォルトでは空白文字が区切り文字
print(myarray)  # デフォルトでは読み込んだ値は浮動小数点数値となる
#[[0. 1. 2.]
# [3. 4. 5.]
# [6. 7. 8.]]

# データ型を指定
myarray = np.loadtxt(filename, dtype=int)  # 全てのフィールドが整数と指定
print(myarray)
#[[0 1 2]
# [3 4 5]
# [6 7 8]]

# 読み込むCSVファイルの内容を確認
filename = 'nptest1.csv'
print(Path(filename).read_text())
#0,1,2  # 数値がカンマで区切られている
#3,4,5
#6,7,8

# 区切り文字を指定
myarray = np.loadtxt(filename, delimiter=','# 区切り文字としてカンマを指定
print(myarray)
#[[0. 1. 2.]
# [3. 4. 5.]
# [6. 7. 8.]]

myarray = np.loadtxt(filename)  # ValueError:デフォルトは空白文字が区切り文字

# 読み込むCSVファイルの内容を確認
filename = 'nptest2.csv'
print(Path(filename).read_text())
#col1 col2 col3  # ヘッダーあり。数値が空白文字で区切られている
#0 1 2
#3 4 5
#6 7 8

# 先頭行を読み飛ばす
myarray = np.loadtxt(filename, skiprows=1# 先頭の1行を読み飛ばす
print(myarray)
#[[0. 1. 2.]
# [3. 4. 5.]
# [6. 7. 8.]]

# 読み込むCSVファイルの内容を確認
filename = 'nptest3.csv'
with open(filename, encoding='utf8') as f:
    print(f.read())
#一色 25 170  # 文字列/数値/数値が空白文字で区切られている
#かわさき 80 168

# 読み込む列を指定する
myarray = np.loadtxt(filename, usecols=[1, 2], encoding='utf8')
print(myarray)
#[[ 25. 170.]
# [ 80. 168.]]

# 列ごとに内容を取り出す(転置)
ages, heights = np.loadtxt(filename, unpack=True, usecols=[1, 2], encoding='utf8')
print(ages)  # [25. 80.]
print(heights)  # [170. 168.]

# numpy.genfromtxt関数

# 読み込むCSVファイルの内容を確認
filename = 'nptest4.csv'
with open(filename, encoding='utf8') as f:
    print(f.read())
#name age height  # ヘッダーあり。文字列/数値/数値が空白文字で区切られている
#一色 25 170
#かわさき 80 168

# 基本的な読み込み
myarray = np.genfromtxt(filename, encoding='utf8')
print(myarray)
#[[ nan  nan  nan]  # 数値以外はnanとされている
# [ nan  25. 170.]
# [ nan  80. 168.]]
print(myarray.dtype)  # float64

# 各フィールドの値からデータ型を判定
myarray = np.genfromtxt(filename, encoding='utf8', dtype=None)
print(myarray)
#[['name' 'age' 'height']
# ['一色' '25' '170']
# ['かわさき' '80' '168']]
print(myarray.dtype)  # <U6(全てが6文字以下の文字列と判定された)

# 1行目をヘッダーとして扱い、各列のデータ型を明示的に指定
myarray = np.genfromtxt(filename, names=True, dtype='U4,f,f', encoding='utf8')
print(myarray)  # [('一色', 25., 170.) ('かわさき', 80., 168.)]
print(myarray.dtype)  # [('name', '<U4'), ('age', '<f4'), ('height', '<f4')]

# 読み込むCSVファイルの内容を確認
filename = 'nptest5.csv'
with open(filename, encoding='utf8') as f:
    print(f.read())
#0,,2  # 各行に欠損している値がある
#,4,5
#6,,8

# 欠損値をnanで埋める
myarray = np.genfromtxt(filename, delimiter=',', encoding='utf8')
print(myarray)
#[[ 0. nan  2.]  # 欠損している部分の値はnanになる
# [nan  4.  5.]
# [ 6. nan  8.]]

myarray = np.loadtxt(filename, delimiter=',', encoding='utf8'# ValueError

# 欠損値を埋める値を指定する
myarray = np.genfromtxt(filename, delimiter=',', filling_values=-1, encoding='utf8')
print(myarray)
#[[ 0. -1.  2.]
# [-1.  4.  5.]
# [ 6. -1.  8.]]


 NumPyを使ったCSVファイルからの読み込みについては「CSVファイルから読み込みを行うには(NumPy編)」を参照のこと。

NumPyを使った書き込み(numpy.savetxt関数)

import numpy as np
from pathlib import Path

x = np.random.randn(2, 3# 以下の値は一例
print(x)
#[[-2.45567984  1.33310634  0.59013369]
# [ 0.25731195  0.78458477 -0.64572527]]

# 基本的な使い方
np.savetxt('test.csv', x)
print(Path('test.csv').read_text())
#-2.455679835942072398e+00 1.333106339746787494e+00 5.901336922847821853e-01
#2.573119457585911207e-01 7.845847696453233100e-01 -6.457252711716952032e-01

# 区切り文字を変更する
np.savetxt('test.csv', x, delimiter=','# 区切り文字をカンマ「,」に
print(Path('test.csv').read_text())
#-2.455679835942072398e+00,1.333106339746787494e+00,5.901336922847821853e-01
#2.573119457585911207e-01,7.845847696453233100e-01,-6.457252711716952032e-01

# 書き出すフォーマットの指定

# 指数表記
np.savetxt('test.csv', x, fmt='%.8e'# 小数点以下の精度を8桁に
print(Path('test.csv').read_text())
#-2.45567984e+00 1.33310634e+00 5.90133692e-01
#2.57311946e-01 7.84584770e-01 -6.45725271e-01

np.savetxt('test.csv', x, fmt='%18.8e'# 最小の出力幅を指定
print(Path('test.csv').read_text())
#   -2.45567984e+00     1.33310634e+00     5.90133692e-01
#    2.57311946e-01     7.84584770e-01    -6.45725271e-01

# 浮動小数点数値(指数表記をしない)
np.savetxt('test.csv', x, fmt='%12.8f'# 精度の後に「f」を指定
print(Path('test.csv').read_text())
# -2.45567984   1.33310634   0.59013369
#  0.25731195   0.78458477  -0.64572527

# 左寄せ
np.savetxt('test.csv', x, fmt='%-18.8e'# 「-」で左寄せを指定
print(Path('test.csv').read_text())
#-2.45567984e+00    1.33310634e+00     5.90133692e-01   
#2.57311946e-01     7.84584770e-01     -6.45725271e-01 

# 符号を常に付加
np.savetxt('test.csv', x, fmt='%+18.8e'# 「+」で符号を常に付加
print(Path('test.csv').read_text())
#   -2.45567984e+00    +1.33310634e+00    +5.90133692e-01
#   +2.57311946e-01    +7.84584770e-01    -6.45725271e-01

# 0埋め
np.savetxt('test.csv', x, fmt='%018.8e'# 「0」で0埋めを指定
print(Path('test.csv').read_text())
#-0002.45567984e+00 00001.33310634e+00 00005.90133692e-01
#00002.57311946e-01 00007.84584770e-01 -0006.45725271e-01

# 整数値
nums = np.array([[111, 222, 333],
                 [444, 555, 666]])

np.savetxt('test.csv', nums, fmt='%d')
print(Path('test.csv').read_text())
#111 222 333
#444 555 666

np.savetxt('test.csv', nums, fmt='%.5d'# 0埋め
print(Path('test.csv').read_text())
#00111 00222 00333
#00444 00555 00666

np.savetxt('test.csv', nums, fmt='%6d'# 出力される最小の文字数を指定
print(Path('test.csv').read_text())
#   111    222    333
#   444    555    666

np.savetxt('test.csv', nums, fmt='%6.4d'# 数字の最小文字数を指定
print(Path('test.csv').read_text())
#  0111   0222   0333
#  0444   0555   0666

# 改行文字を変更する
np.savetxt('test.csv', x, newline='\n\n')
print(Path('test.csv').read_text())
#-2.455679835942072398e+00 1.333106339746787494e+00 5.901336922847821853e-01
#
#2.573119457585911207e-01 7.845847696453233100e-01 -6.457252711716952032e-01
#

# ヘッダーを付加する
np.savetxt('test.csv', x, header='col1 col2 col3')
print(Path('test.csv').read_text())
## col1 col2 col3
#-2.455679835942072398e+00 1.333106339746787494e+00 5.901336922847821853e-01
#2.573119457585911207e-01 7.845847696453233100e-01 -6.457252711716952032e-01

# フッターを付加する
np.savetxt('test.csv', x, footer='generated: 2021/08/27')
print(Path('test.csv').read_text())
#-2.455679835942072398e+00 1.333106339746787494e+00 5.901336922847821853e-01
#2.573119457585911207e-01 7.845847696453233100e-01 -6.457252711716952032e-01
## generated: 2021/08/27


 NumPyを使ったCSVファイルへの書き込みについては「CSVファイルに書き込みを行うには(NumPy編)」を参照のこと。

pandasを使った読み込み(pandas.read_csv関数)

Copyright© Digital Advantage Corp. All Rights Reserved.

RSSについて

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

メールマガジン登録

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