Pythonでデータ分析のデモ用にそれっぽいCSVファイルをつくる


Pythonを使ってデータ分析のデモ用にそれっぽいCSVファイルをつくる関数をつくりました。
データ分析で関係者にデモを見せたり、実データが扱えない状況でのテストデータ作成などにご利用ください。

コードの全体を記事末尾にまとめています。(コピペ用)

本記事の想定読者

  • Pythonユーザー
  • データ分析のデモ用にそれっぽいCSVファイルをつくりたい
    (それっぽいデータの方が関係者への説明に使いやすいので)

実際の関数

基本方針

  • randomを使って予め設定した範囲・選択肢から適当な値を取り出す
  • 日付、時刻、数値、文字列の選択肢に対してそれぞれ適した処理をする

今回の設定

今回は以下のような設定のもとでCSVファイルを作成します。

データ範囲・選択肢の設定内容
  - 日付は2022年1月1日から1年間(364日後まで)
  - 時刻は午前9時(AM9)から午後18時(PM6)まで
  - 数値は0から100まで
  - 文字列の選択肢は適当に

1. データの範囲・選択肢の設定

  • データ生成の度に結果がばらつくのを避けるためrandom.seed()を設定する
  • 日付、時刻、整数値の範囲を設定するためのnamedtupleを作成する
  • 各列の範囲・選択肢の内容をcoldictに代入する
必要なライブラリのimportとデータの範囲・選択肢の設定
import random
from random import randint
from collections import OrderedDict, namedtuple
from datetime import datetime, timedelta

random.seed(0)

DateRange = namedtuple('DateRange', ['start', 'max_range'])
TimeRange = namedtuple('TimeRange', ['start', 'end'])
IntRange = namedtuple('IntRange', ['min', 'max'])

# 以下今回固有の設定
Y2022 = datetime(year=2022, month=1, day=1)
ONE_YEAR = 364
date_range = DateRange(Y2022, ONE_YEAR)

AM9 = 9 * 60 * 60
PM6 = 18 * 60 * 60
time_range = TimeRange(AM9, PM6)

num_range = IntRange(0, 100)

# 設定をcoldictに代入していく
coldict = OrderedDict()
coldict = {
    '日付':date_range,
    '時刻':time_range,
    '数値':num_range,
    '列A':['elemA1', 'elemA2', 'elemA3'],
    '列B':['elemB1', 'elemB2', 'elemB3'],
    '列C':['elemC1', 'elemC2', 'elemC3'],
}

2. 1行分のデータを作成する関数をつくる

  • 列の中身の型をisinstanceで判別して処理を分岐させる
  • coldictの設定をもとにランダムに値を生成していく
CSVデータの1行分を書き出す関数
def make_random_csv_row(coldict):
    """ランダムなCSVデータの1行分を生成する"""
    row = ''
    for col, elems in coldict.items():
        if isinstance(elems, DateRange):
            date = elems.start + timedelta(days=randint(0, elems.max_range))
            row += f'{date.date()},'
        elif isinstance(elems, TimeRange):
            row += f'{timedelta(seconds=randint(elems.start, elems.end))},'
        elif isinstance(elems, IntRange):
            row += f'{randint(elems.min, elems.max)},'
        else:
            row += f'{random.choice(coldict[col])},'
    row = row.rstrip(',')
    return row

これを実行すると筆者の環境では以下のような結果が返ってきます。

ランダムに生成されたCSVファイルの1行
'2022-07-17,15:53:56,53,elemA1,elemB2,elemC3'

これがCSVファイルの1行になります。
あとはこれを欲しい行数の分だけ生成して書き出せばOKです。

3. 行数を指定してCSVファイルを出力する

  • 範囲・選択肢の辞書(coldict)、ファイル名(filename)、行数(num_rows)を引数に設定する
  • 関数を実行してCSVファイルを書き出す
ランダムなCSVファイルを作成する関数
def make_random_csv(coldict, filename, num_rows=100):
    """指定した行数のランダムなCSVデータを生成する"""
    output = []
    output.append(','.join(coldict.keys()))
    for i in range(num_rows):
        output.append(make_random_csv_row(coldict))
    with open(filename, mode='w')as f:
        output = '\n'.join(output)
        f.writelines(output)

これを実行した結果のCSVファイルの先頭5行を抜粋します。

関数の実行例
make_random_csv(coldict, filename='output.csv', num_row=100)

output.csv(先頭5行)
日付,時刻,数値,列A,列B,列C
2022-07-17,15:53:56,53,elemA1,elemB2,elemC3
2022-09-06,12:41:08,100,elemA2,elemB2,elemC2
2022-10-26,17:06:57,27,elemA3,elemB1,elemC2
2022-03-13,15:52:46,12,elemA3,elemB2,elemC3

これでCSVファイルの完成です。

まとめ

  • データ分析のデモ用にそれっぽいCSVファイルがつくれるようになった!
  • 関係者にデモを見せる時もちょっと見栄えがよくなるかも

コード全文

コード全文(クリックで表示)
コード全文
import random
from random import randint
from collections import OrderedDict, namedtuple
from datetime import datetime, timedelta

random.seed(0)

DateRange = namedtuple('DateRange', ('start', 'max_range'))
TimeRange = namedtuple('TimeRange', ['start', 'end'])
IntRange = namedtuple('IntRange', ['min', 'max'])

def make_random_csv_row(coldict):
    """ランダムなCSVデータの1行分を生成する"""
    row = ''
    for col, elems in coldict.items():
        if isinstance(elems, DateRange):
            date = elems.start + timedelta(days=randint(0, elems.max_range))
            row += f'{date.date()},'
        elif isinstance(elems, TimeRange):
            row += f'{timedelta(seconds=randint(elems.start, elems.end))},'
        elif isinstance(elems, IntRange):
            row += f'{randint(elems.min, elems.max)},'
        else:
            row += f'{random.choice(coldict[col])},'
    row = row.rstrip(',')
    return row


def make_random_csv(coldict, filename, num_rows=100):
    """ランダムなCSVデータを指定した行数分だけ生成する"""
    output = []
    output.append(','.join(coldict.keys()))
    for i in range(num_rows):
        output.append(make_random_csv_row(coldict))
    with open(filename, mode='w')as f:
        output = '\n'.join(output)
        f.writelines(output)


# 記事内で使ったサンプル
Y2022 = datetime(year=2022, month=1, day=1)
ONE_YEAR = 364
date_range = DateRange(Y2022, ONE_YEAR)

AM9 = 9 * 60 * 60
PM6 = 18 * 60 * 60
time_range = TimeRange(AM9, PM6)

num_range = IntRange(0, 100)

coldict = OrderedDict()
coldict = {
    '日付':date_range,
    '時刻':time_range,
    '数値':num_range,
    '列A':['elemA1', 'elemA2', 'elemA3'],
    '列B':['elemB1', 'elemB2', 'elemB3'],
    '列C':['elemC1', 'elemC2', 'elemC3'],
}

make_random_csv(coldict, 'output.csv', 100)