python

【Python】csvファイルの扱い方

python

CSVファイル読み込み時に使うメソッド(ファイルを開く、読み込む)です。

open(ファイルを開く)

sample = open("ファイルのパス", "r", encoding="文字コード")
# :
sample.close()    # openしたら、必ずcloseする!

# ↓の書き方もOK
# with:ファイルを一定期間操作する構文(自動でクローズしてくれる)
with open("./ファイル名.csv", "r", encoding="文字コード") as sample:
    for row in csv.reader(sample):
        # :
    
    # ファイル全体を文字列として読み込み
    f.read()

    # ファイル全体をリストとして読み込み(最終行以外は末尾に改行コード\nを含む)
    f.readlines()
   # 末尾の改行コードを削除
    [s.rstrip() for s in f.readlines()]

    # 1行ずつ読み込み
    for s_line in f:
        repr(s_line)

    # 1行ずつ進める(行数を超えるとエラー)
    repr(next(f))
    repr(next(f))
    # readline()でも1行ずつ取得できるが、行数を超えてもエラーにならない(空文字列が返される)
    repr(f.readline())
    repr(f.readline())

with open('hoge.txt', 'w') as f:
    # リストの書き込み(改行コードは挿入されない)
    f.writelines(l)    # 引数は文字列のリストのみ
    # リストの要素ごとに改行して書き込む
    f.write('\n'.join(l))

    # 空ファイル作成
    pass
引数
moder:読み込み用(デフォルト)
w:書き込み用
x:新規作成 + 書き込み用(既存ファイルがあるとエラー)
a:追記用(末尾に追記)
b:バイナリモード(r, w, aと一緒に指定)
t:テキストモード(r, w, aと一緒に指定)
+:更新用(r, w, a, xと一緒に指定)
encoding文字コードの指定。
例)utf_8、ms932、euc_jp、shift_jis
newlineuniversal newlines モードの制御。
例)None、”、’\n’、’\r’、’\r\n’

読み込む

  • csv.reader:ファイル読み込み(リスト型で返す)
  • csv.Dictreader:ファイル読み込み(辞書型で返す)

csv.reader、csv.DictReader(リスト型・辞書型)

返す型が異なる(reader:リスト型、DictReader:辞書型)。

import csv

# リスト型: reader の場合
sample_file = csv.reader(sample_file, delimiter=",", doublequote=True, lineterminator="\r\n", quotechar='"', skipinitialspace=True)
header = next(sample_file)   # ヘッダー一覧
for row in sample_file:
    # インデックスでアクセス

# 辞書型: DictReader の場合
sample_file = csv.DictReader(sample_file, delimiter=",", doublequote=True, lineterminator="\r\n", quotechar='"', skipinitialspace=True)
for row in sample_file:
    # カラム名でアクセス(例:row["カラム名"]、row.get("カラム名"))
引数
delimiter区切り文字。
デフォルト:「,」
doublequoteフィールド内のquotecharがその文字である場合に、どのようにクオートするか。
デフォルト:True
・True:この文字は二重化
・False:escapechar は quotechar 前
escapecharエスケープ用の文字列。
lineterminator書き込み時に、行の末端を表す文字。
デフォルト:「\r\n」
※readerでは、デフォルトで「\r\n」 を行の末端とする
quotechar特殊文字(delimiter、quotechar など)、改行文字を含むフィールドのクオート時に使う文字列。
skipinitialspacedelimiter 直後の空白は無視される。
quotingクオートがいつ生成されるか、reader によって認識されるかを制御する。
・csv.QUOTE_MINIMAL:特別な文字を含む要素のみを引用符で囲む(デフォルト)
・csv.QUOTE_ALL:全要素を引用符で囲む
・quoting.QUOTE_NONNUMERIC:数値でない要素を引用符で囲む
・csv.QUOTE_NONE:全要素も引用符で囲まない(escapecharの文字指定が必要)

pandas(DataFrameの形で読み込む)

データ分析用のライブラリ。
DataFrameオブジェクト(2次元配列)で読み込まれるので、後の操作がしやすい。
拡張子が.gz.bz2.zip.xz.zst.tar.tar.gz.tar.xz.tar.bz2の場合は、自動で展開してくれる(複数ファイルはNG)。

read_csvの引数
filepath_or_bufferファイルパス、readメソッドをもったオブジェクトの指定。
sep区切り文字。
デフォルト:「,」
delimiter区切り文字(sep の代わりに 指定可能)。
encoding文字コード。
例)ms932, utf_8
escapecharエスケープ用の文字列。
quotechar特殊文字(delimiter、quotecharなど)、改行文字を含むフィールドのクオート時に使う文字列。
index_colindexとして使いたい列の列番号を0始まりで指定する。
usecols特定列だけ読み込む。
・列番号 or 列名をリストで指定する。
・ラムダ式も指定可能(列数が多いファイルから少数の列を除外する時は、列名・列番号を指定するより楽)。
skiprows特定行をスキップ(除外)。
・整数:先頭〜n行をスキップ。
・行番号をリストで指定もできる(スキップする行を指定する)。
・ラムダ式も指定可能(行数が多いファイルから特定行だけ読み込む時は、スキップする行番号を指定するより楽)。
※headerがある場合、headerが0行目として扱われる
skipfooterファイルの末尾〜n行数をスキップする(整数で指定)。
※環境によってはWarningが出る(engine='python'を指定すればOK)。
nrows最初〜n行を読み込む。
※headerがある場合、headerは含まれない。
headerNone or 0と指定すると、0始まりの連番をカラム名にする。
headerとして扱う行番号を0始まりで指定も可能(指定より上の行は無視される)。
import pandas as pd

sample = pd.read_csv(filepath_or_buffer="hoge/ファイル名.csv", encoding="ms932", sep=",")

# 行数
sample.size           # 10
len(sample)
# カラム数
len(sample.columns)    # 3
# 次元
sample.shape          # (10, 3)

# カラムの取得
sample.columns     # Index(['名前', 'カナ', '年齢'], dtype='object')
sample.columns[2]   # 年齢

# 値の取得
# 配列で取得(型:numpy.ndarray)
sample.values         # [['山田' 'ヤマダ' 24], ['田中' 'タナカ' 27],..]
# 行・カラムのインデックスで取得
sample.values[0, 1]   # 山田

# 列追加
sample['追加'] = ['aa', 'bb',..]
#    名前    カナ   年齢   追加
# 0  山田   ヤマダ   24    aa
# 1  田中   タナカ   27    bb
# :

取得行数の指定

# 先頭〜指定行数(型:pandas.core.frame.DataFrame)
sample.head(3)
#    名前    カナ   年齢
# 0  山田   ヤマダ   24
# 1  田中   タナカ   27
# 2  鈴木   スズキ   21

# 指定行〜最後(型:pandas.core.frame.DataFrame)
sample.tail(3)
#    名前    カナ   年齢
# 7  木村   キムラ   34
# 8  田村   タムラ   23
# 9  村田   ムラタ   29

行、カラムの指定(loc、iloc、ix)

  • loc:行のインデックス × カラム名
  • iloc:行のインデックス × カラムのインデックス
  • ix:行のインデックス × カラム名 or カラムのインデックス
# カラム指定して全行取得
sample[['名前', 'カナ']]
#    名前    カナ
# 0  山田   ヤマダ
# 1  田中   タナカ
# :

# loc
sample.loc[:,['名前', '年齢']]   # 全行 × 指定カラム
#     名前  年齢
# 0   山田   24
# 1   田中   27
# :
# 9   村田   29
sample.loc[1:2, ['名前', '年齢']] # 2-3行目 × 指定カラム
#     名前  年齢
# 1   田中   27
# 2   鈴木   21

# iloc
sample.iloc[:, 2]       # 全行 × 指定カラム(index=2)
# 0    24
# 1    27
# 5    29
sample.iloc[0:3, 1:2]   # 1-3行目 × 指定カラム(index=1-2)
#     カナ   年齢
# 0  ヤマダ   24
# 1  タナカ   27
# 2  スズキ   21

# ix(カラム名、インデックスのどちらもOK)
sample.ix[0:3, ['名前', '年齢']]  # 1-4行目 × 指定カラム
#     名前   年齢
# 0   山田    24
# 1   田中    27
# :
# 3   井口    30
sample.ix[0:3, 3:6]              # 1-4行目 × 指定カラム(index=1-2)
#    カナ   年齢
# 0  ヤマダ   24
# 1  タナカ   27
# :
# 3  イグチ   30

絞り込み条件の指定

sample[sample['年齢'] > 30]
sample.query('年齢 > 30')
#    名前    カナ   年齢
# 4  白井   シライ   37
# 6  真田   サナダ   31
# 7  木村   キムラ   34

# 複数条件
sample[(sample['年齢'] > 30) & (sample['番号'] >= sample['番号2'])]
sample[(sample['年齢'] > 30) | (sample['番号'] >= sample['番号2'])]
sample[(sample['名前'].isin(['田中', '鈴木']))]

numpy.loadtxt、np.genfromtxt

import numpy as np
from pathlib import Path

# numpy.loadtxt
# ファイルの内容
Path('ファイル名.csv').read_text()   # 区切り文字:空白文字
# 0 1 2
# 3 4 5
# 6 7 8

# np.loadtxt
np.loadtxt('ファイル名.csv')  # 区切り文字:空白文字(デフォルト:浮動小数点数値)
# [[0. 1. 2.], [3. 4. 5.], [6. 7. 8.]]
# データ型の指定
np.loadtxt('ファイル名.csv', dtype=int)  # 整数に指定
# [[0 1 2], [3 4 5], [6 7 8]]


# ファイルの内容
Path('ファイル名.csv').read_text())  # 区切り文字:カンマ
# 0, 1, 2
# 3, 4, 5
# 6, 7, 8

# 区切り文字の指定
np.loadtxt('ファイル名.csv', delimiter=',')  # 区切り文字:カンマ
# [[0. 1. 2.], [3. 4. 5.], [6. 7. 8.]]

np.loadtxt('ファイル名.csv')  # 区切り文字:空白文字
# エラー


# ファイルの内容
Path('ファイル名.csv').read_text()  # ヘッダーあり。区切り文字:空白文字
# col1 col2 col3
#  0    1    2
#  3    4    5
#  6    7    8

# 先頭行を読み飛ばす
np.loadtxt('ファイル名.csv', skiprows=1)
# [[0. 1. 2.], [3. 4. 5.], [6. 7. 8.]]


# ファイルの内容
with open('ファイル名.csv', encoding='utf8') as f:
    print(f.read())  # 区切り文字:空白文字
# 山田 ヤマダ 25
# 田中 タナカ 80

# 列を指定
np.loadtxt('ファイル名.csv', usecols=[1, 2], encoding='utf8')
# [[ヤマダ 25.], [タナカ 80.]]

# 列ごとに取り出す(転置)
kanas, ages = np.loadtxt('ファイル名.csv', unpack=True, usecols=[1, 2], encoding='utf8')
kanas     # [ヤマダ タナカ]
ages      # [25. 80.]


# numpy.genfromtxt
# ファイルの内容
with open('ファイル名.csv', encoding='utf8') as f:
    print(f.read())  # ヘッダーあり。区切り文字:空白文字
# 名前  カナ  年齢
# 山田 ヤマダ  25
# 田中 タナカ  45

# 読み込み
myarray = np.genfromtxt('ファイル名.csv', encoding='utf8')  # 数値以外はnan
# [[nan nan 25], [nan nan 45]]
myarray.dtype  # float64

# 各フィールドの値からデータ型を判定
myarray = np.genfromtxt('ファイル名.csv', encoding='utf8', dtype=None)
# [['名前' 'カナ' '年齢'], ['山田' 'ヤマダ' '25'], ['田中' 'タナカ' '45']]
myarray.dtype  # <U6(全てが6文字以下の文字列と判定)

# 1行目をヘッダーとして、データ型指定
myarray = np.genfromtxt('ファイル名.csv', names=True, dtype='U4,f,f', encoding='utf8')
# [('山田', 'ヤマダ', 25.) ('田中', 'タナカ', 45.)]
myarray.dtype  # [('名前', '<U2'), ('カナ', '<f4')]


# ファイルの内容
with open('ファイル名.csv', encoding='utf8') as f:
    print(f.read())
# 0, , 2
# , 4, 5
# 6, , 8

np.loadtxt('ファイル名.csv', delimiter=',', encoding='utf8')
# エラー

# 欠損値をnanで埋める
np.genfromtxt('ファイル名.csv', delimiter=',', encoding='utf8')
# [[ 0. nan  2.], [nan  4.  5.], [ 6. nan  8.]]
# 欠損値を-1で埋める
np.genfromtxt('ファイル名.csv', delimiter=',', filling_values=-1, encoding='utf8')
# [[ 0. -1.  2.], [-1.  4.  5.], [ 6. -1.  8.]]

書き込み

  • csv.writer:ファイル書き込み(リスト型で書き込む)
  • csv.DictWriter:ファイル書き込み(辞書型で書き込む)

csv.writer.writerow/writerows、csv.DictWriter(リスト型、辞書型)

import csv
from pathlib import Path

# 1行の書き込み
with open('ファイル名.csv', 'w', newline='') as f:
    writer = csv.writer(f)
    writer.writerow(['山田', 'ヤマダ', 25])
# 山田, ヤマダ, 25
# 複数行の書き込み
with open('ファイル名.csv', 'w', newline='') as f:
    writer = csv.writer(f)
    writer.writerows([['山田', 'ヤマダ', 25], ['田中', 'タナカ', 45,]])
# 山田, ヤマダ, 25
# 田中, タナカ, 45

# 行頭にヘッダー書き込み
with open('ファイル名.csv', 'w', newline='') as f:
    writer = csv.writer(f)
    writer.writerow(['名前', 'カナ', '年齢'])
    writer.writerows([['山田', 'ヤマダ', 25], ['田中', 'タナカ', 45]])
# 名前,  カナ, 年齢
# 山田, ヤマダ, 25
# 田中, タナカ, 45


# 区切り文字変更(カンマ → タブ)
with open('ファイル名.tsv', 'w', newline='') as f:
    writer = csv.writer(f, delimiter='\t')
    writer.writerow(['山田', 'ヤマダ', 25])
repr(Path('ファイル名.tsv').read_text())
# "'山田\\tヤマダ\\t25\\n'"


# 全フィールドを引用符で囲む(デフォルト:ダブルクオート)
with open('ファイル名.csv', 'w', newline='') as f:
    writer = csv.writer(f, quoting=csv.QUOTE_ALL)
    writer.writerow(['山田', 'ヤマダ', 25])
# "山田", "ヤマダ", "25"


# 数値以外のフィールドをシングルクオートで囲む
with open('ファイル名.csv', 'w', newline='') as f:
    writer = csv.writer(f, quoting=csv.QUOTE_NONNUMERIC, quotechar="'")
    writer.writerow(['山田', 'ヤマダ', 25])
# '山田', 'ヤマダ', 25


# 辞書要素の書き込み
samples = [
    dict(zip(['名前', 'カナ', '年齢'], row)) for row in [['山田', 'ヤマダ', 25], ['田中', 'タナカ', 45,]]
]
# [{'名前': '山田', 'カナ': 'ヤマダ', '年齢': 25}, {'名前': '田中', 'カナ': 'タナカ', 'age': 45}]
with open('ファイル名.csv', 'w', newline='') as f:
    writer = csv.DictWriter(f, fieldnames=['名前', 'カナ', '年齢'])
    writer.writeheader()    # ヘッダーの書き込み
    writer.writerows(samples)
# 名前, カナ, 年齢
# 山田, ヤマダ, 25
# 田中, タナカ, 45

numpy.savetxt

import numpy as np
from pathlib import Path

np.random.randn(2, 3)
# [[-2.45567984  1.33310634  0.59013369], [ 0.25731195  0.78458477 -0.64572527]]

np.savetxt('ファイル名.csv', x)
# -2.455679835942072398e+00 1.333106339746787494e+00 5.901336922847821853e-01
# 2.573119457585911207e-01 7.845847696453233100e-01 -6.457252711716952032e-01

# 区切り文字の変更
np.savetxt('ファイル名.csv', x, delimiter=',')  # 区切り文字:「,」
# -2.455679835942072398e+00,1.333106339746787494e+00,5.901336922847821853e-01
# 2.573119457585911207e-01,7.845847696453233100e-01,-6.457252711716952032e-01

# フォーマットの指定
np.savetxt('ファイル名.csv', x, fmt='%.8e')         # 指数表記: 小数点以下の精度を8桁に
# -2.45567984e+00 1.33310634e+00 5.90133692e-01
# 2.57311946e-01 7.84584770e-01 -6.45725271e-01
np.savetxt('ファイル名.csv', x, fmt='%18.8e')       # 最小の出力幅を指定
#   -2.45567984e+00     1.33310634e+00     5.90133692e-01
#    2.57311946e-01     7.84584770e-01    -6.45725271e-01
# 浮動小数点数値(指数表記をしない)
np.savetxt('ファイル名.csv', x, fmt='%12.8f')       # 精度の後に「f」を指定
# -2.45567984   1.33310634   0.59013369
#  0.25731195   0.78458477  -0.64572527
np.savetxt('ファイル名.csv', x, fmt='%-18.8e')      # 左寄せ
# -2.45567984e+00    1.33310634e+00     5.90133692e-01   
# 2.57311946e-01     7.84584770e-01     -6.45725271e-01 
np.savetxt('ファイル名.csv', x, fmt='%+18.8e')      # 符号を常に付加
#   -2.45567984e+00    +1.33310634e+00    +5.90133692e-01
#   +2.57311946e-01    +7.84584770e-01    -6.45725271e-01
np.savetxt('ファイル名.csv', x, fmt='%018.8e')      # 0埋め
# -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('ファイル名.csv', nums, fmt='%d')
# 111 222 333
# 444 555 666
np.savetxt('ファイル名.csv', nums, fmt='%.5d')   # 0埋め
# 00111 00222 00333
# 00444 00555 00666
np.savetxt('ファイル名.csv', nums, fmt='%6d')    # 最小の文字数を指定
#   111    222    333
#   444    555    666
np.savetxt('ファイル名.csv', nums, fmt='%6.4d')  # 数字の最小文字数を指定
#  0111   0222   0333
#  0444   0555   0666
np.savetxt('ファイル名.csv', x, newline='\n\n')  # 改行文字を変更
# -2.455679835942072398e+00 1.333106339746787494e+00 5.901336922847821853e-01
#
# 2.573119457585911207e-01 7.845847696453233100e-01 -6.457252711716952032e-01
#
np.savetxt('ファイル名.csv', x, header='col1 col2 col3') # ヘッダー付加
# col1 col2 col3
# -2.455679835942072398e+00 1.333106339746787494e+00 5.901336922847821853e-01
# 2.573119457585911207e-01 7.845847696453233100e-01 -6.457252711716952032e-01
np.savetxt('ファイル名.csv', x, footer='フッター')        # フッター付加
Path('ファイル名.csv').read_text()
# -2.455679835942072398e+00 1.333106339746787494e+00 5.901336922847821853e-01
# 2.573119457585911207e-01 7.845847696453233100e-01 -6.457252711716952032e-01
# フッター