PythonでCSVの読み込み書き込み|CSV

python_csv_pc Python
python_csv_pc
この記事は約13分で読めます。

はじめに

CSVファイルの読み込みや書き込みをしたいときは、Python標準ライブラリのcsvを使用します。

CSVファイルを読み込みたいときはcsv.DictReaderを使い、書き込みたいときはcsv.DictWriterを使います。

タイトル行を意識する場合はcsv.DictReaderやcsv.DictWriterを使いますが、そうでない場合は単純にcsv.readerやcsv.writerで処理します。

今回のPython標準ライブラリであるCSVとは別件ですが、CSV操作をする場合はJupyter Notebookでpandasをインポートして逐次、CSVの読み込みや書き込みを確認する方が便利かもしれません。

興味があればそちらも試して頂ければと思いますが、それでも純粋に標準ライブラリのCSVを使用する機会もあるかと思いますので、載せていきたいと思います。

CSVファイルの読み込み(一行ずつ)

CSVファイルを一行ずつ読み込みをしたい場合は、Python標準ライブラリのcsvをimportした後、csv.readerを使ってfor文で回します。

csv.DictReader()を使ってもいいのですが、出力結果が異なるので使い分ければいいかなと思います。

# sample.csvの内容
fruit,count
apple,10
banana,20
orange,30

# read csvfile
import csv

with open('sample.csv', 'r') as csvfile:
    #reader = csv.DictReader(csvfile)
    reader = csv.reader(csvfile)
    for row in reader:
        print(row)

# 実行結果
['fruit', 'count']
['apple', '10']
['banana', '20']
['orange', '30']

因みに、csv.DictReader()を使った場合はこちら。

import csv

with open('sample.csv', 'r') as csvfile:
    reader = csv.DictReader(csvfile)
    #reader = csv.reader(csvfile)
    for row in reader:
        print(row)

# 処理結果
OrderedDict([('fruit', 'apple'), ('count', '10')])
OrderedDict([('fruit', 'banana'), ('count', '20')])
OrderedDict([('fruit', 'orange'), ('count', '30')])

csv.DictReader()を使うとタイトル名が含まれる形ですね。

CSVファイルをlist形式として読み込む場合

CSVファイルの各行をlist形式で取得したい場合は、以下のようにcsv.reader()を使用しその戻り値であるオブジェクトをlist()で読み込みます。

import csv

with open('sample.csv', 'r') as csvfile:
    reader = csv.reader(csvfile)
    csv_data = list(reader)
    print(csv_data)

# result
[['fruit', 'count'], ['apple', '10'], ['banana', '20'], ['orange', '30']]

この場合、1行目であるタイトル行も含まれていますので、タイトル行が不要な場合は別途削除用の処理が必要です。

また、要素にアクセスする場合は以下のようにcsv_data[行番号][カラム番号]というふうに指定してあげます。

# 行番号のみ指定(一行分を取得)
print(csv_data[0])

# 処理結果
['fruit', 'count']

# 行番号とカラム番号を指定(指定行の指定列のデータを取得)
 print(csv_data[0][0])

# 処理結果
fruit

今回のように1ファイルだけであれば手作業でタイトル行を削除すればいいかもしれませんが、同一ディレクトリ内に数十個や数百個のCSVファイルが存在しそれら全てを読み込む必要がある場合は、とても手作業では追いつきません。

そういったケースの場合は、別途プログラムを書きましょう。

複数のCSVファイルからタイトル行を削除する

同一ディレクトリ内に複数のCSVファイルが存在し、各CSVファイルのタイトル行を削除したい場合は以下のようにします。

処理の流れとしては、

①ループでCSVファイルをひとつずつ開き、全内容を読み込む。

②タイトル行を無視(スキップ)した後、新規保存。

処理でミスったら終わりなので、事前にバックアップは取っておきましょう。

# sample_csvというディレクトリが今回の処理対象とする
# ディレクトリの中身は、下記「# 処理結果」の通り
import os

for file_name in os.listdir('sample_csv'):
    print(file_name)

# 処理結果
sample01.csv
sample02.csv
sample03.csv
test01.txt
test02.txt

でわ、実際のコードがこちらになります。

import csv
import os

"""
指定したdirectory内にある全csvファイルの1行目にあるタイトル行を削除するスクリプト。
処理後のcsvファイルを保存するdirectory「new」を作成。
"""
os.makedirs('new', exist_ok=True)

target_dir_name = 'sample_csv'
for csv_file_name in os.listdir(target_dir_name):
    if not csv_file_name.endswith('.csv'):
        continue

    # remove title
    print('タイトル行を削除中... ' + csv_file_name)

    # read csvfile
    csv_rows = []
    with open(os.path.join(target_dir_name, csv_file_name), 'r') as f:
        #reader = csv.DictReader(f)
        reader = csv.reader(f)
        for row in reader:
            if reader.line_num == 1:
                continue
            csv_rows.append(row)

    # output csvfile
    saved_dir = os.path.join(os.getcwd(), 'new')
    with open(os.path.join(saved_dir, csv_file_name), 'w', newline='') as f:
        #writer = csv.DictWriter(f)
        writer = csv.writer(f)
        for row in csv_rows:
            writer.writerow(row)

# 処理結果
タイトル行を削除中... sample01.csv
タイトル行を削除中... sample02.csv
タイトル行を削除中... sample03.csv
※newディレクトリに保存された各csvファイルの中身を見ると、タイトル行が削除されていることを確認。

今回はCSVファイルが少なかったですが、数十個、数百個ある場合は威力を発揮すると思います。

CSVファイルの書き込み

CSVファイルの書き込みをしたい場合は、Python標準ライブラリのcsvをimportした後、csv.DictWriterを使用します。

import csv

# output csv
with open('sample.csv', 'w') as csvfile:
    fieldnames = ['first_name', 'last_name']
    writer = csv.DictWriter(csvfile, fieldnames=fieldnames)
    writer.writeheader()
    writer.writerow({'first_name': 'ryoko', 'last_name': 'hirosue'})
    writer.writerow({'first_name': 'kanna', 'last_name': 'hashimoto'})

# output result
    ryoko,hirosue
    
    kanna,hashimoto

ただ、上記のサンプルコードを実行した場合、出力されたCSVファイルをWindows端末で開くと余分な空行が一行含まれてしまいます。

これを防ぐにはwith openのキーワード引数に「newline=”」を付与して実行します。

import csv

# output csv
with open('sample.csv', 'w', newline='') as csvfile:
    fieldnames = ['first_name', 'last_name']
    writer = csv.DictWriter(csvfile, fieldnames=fieldnames)
    writer.writeheader()
    writer.writerow({'first_name': 'ryoko', 'last_name': 'hirosue'})
    writer.writerow({'first_name': 'kanna', 'last_name': 'hashimoto'})

# output result
ryoko,hirosue
kanna,hashimoto

これで余分な空行がなくなりました。

通常使用する際は上記の形が良いと思います。

因みに「writer.writeheader()」は、タイトル行の書き込みをする処理です。

タイトル行が不要な場合は「fieldnames = [‘first_name’, ‘last_name’]」とwriter.writeheader()」は削除してください。

今回書き込んだデータには無かったのですが、あるセルのデータにカンマが含まれていた場合でも、CSVモジュールを使用すれば自動的にダブルクォーテーションで囲ってくれるので安心です。

delimiterで区切り文字を変更する

デフォルトのデリミタはカンマですが、タブに変えてみる場合は以下のようになります。

import csv

with open('test.tsv', 'w', newline='') as f:
    writer = csv.writer(f, delimiter='\t')
    writer.writerow(['apple', 'banana', 'orange'])
    writer.writerow(['grape', 'tomato', 'strawberry'])

# 実行結果
apple	banana	orange
grape	tomato	strawberry

デリミタを変更したい場合は、「delimiter=”」で指定してあげれば大丈夫です。

lineterminatorで改行文字を変更する

改行文字を変更したい場合は、キーワード引数「lineterminator=”」で改行文字を指定します。

デフォルトの場合、Windowsでは「\n」ですがこれを2個「\n\n」にしてみます。

import csv

with open('test.tsv', 'w', newline='') as f:
    writer = csv.writer(f, lineterminator='\n\n')
    writer.writerow(['apple', 'banana', 'orange'])
    writer.writerow(['grape', 'tomato', 'strawberry'])

# 実行結果
apple,banana,orange

grape,tomato,strawberry

指定した通り改行が2個入ってますね。

こんな感じで色々試してみれば良いと思います。

まとめ

CSVファイルを扱うことは多いと思いますが、csv.reader()やcsv.writer()を使うのが一番シンプルかと思います。

はじめはcsv.DictReader()とcsv.DictWriter()を使っていましたが、出力結果がいまいちわかりずらかったので、csv.reader()やcsv.writer()との違いをあまり考えていませんでした。

タイトル行を意識する場合は、csv.DictReader()やcsv.DictWriter()を使う方がよいと思います。

とりあえず簡単に載せてみましたが、肉付けできるところは徐々に載せていきたいなと思っています。

ご参考になれば幸いです。

コメント

タイトルとURLをコピーしました