← Files tochi-satei-kunARCHIVED FILE

skills/tochi-satei-kun/samples/_generate_dummy.py

7.58 KB · Oct 5, 2026 · 18:30 UTC

↓ Download file

# Copyright 2026 Koichi Matsuda / SignalYield Advisory
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

"""ダミーサンプル生成(実MLIT CSV受領前の暫定)。
実データ受領後はこのスクリプトを廃棄、または列名整合のリファレンスとして残す。
東京都港区の宅地(土地)を想定して合理的な分布で30件生成。
"""
import csv
import json
import math
import random
from pathlib import Path

random.seed(42)
HERE = Path(__file__).parent

DISTRICTS = ["麻布十番", "赤坂", "青山", "三田", "芝", "高輪", "白金", "六本木"]
STATIONS = {
    "麻布十番": "麻布十番", "赤坂": "赤坂", "青山": "表参道",
    "三田": "三田", "芝": "芝公園", "高輪": "高輪台",
    "白金": "白金台", "六本木": "六本木",
}
SHAPES = ["整形", "不整形", "袋地"]
SHAPE_W = [0.70, 0.20, 0.10]
ROAD_TYPES = ["区道", "都道", "私道"]  # MLIT実分類に整合
ROAD_W = [0.75, 0.10, 0.15]
ROAD_DIRS = ["北", "東", "南", "西", "北東", "南東", "南西", "北西"]
QUARTERS = [(2025, 3), (2025, 4), (2026, 1)]  # asof 2026-05-01 から見て直近1年内


SOUTH_DIRS = {"南", "南東", "南西"}


PRIVATE_ROAD = "私道"


def gen_unit_price(area, walk_min, shape, road_type, road_dir, kanguchi, road_width):
    """log-linear モデルで単価を生成(テスト時の符号判定の真値となる)。
    被説明変数: ln(単価/㎡)
      面積大→単価減(不動産通則)
      駅遠い→単価減
      不整形/袋地→単価減
      私道→単価減
      南向き→単価増
      間口広い→単価増
      道路幅員広い→単価増
    """
    base = math.log(4_000_000)  # 港区の標準単価400万/㎡
    eff = (
        -0.10 * (math.log(area) - math.log(100))
        - 0.03 * walk_min
        + 0.05 * (math.log(kanguchi) - math.log(6.0))
        + 0.04 * (math.log(road_width) - math.log(5.0))
        + (0.06 if road_dir in SOUTH_DIRS else 0.0)
        - (0.10 if shape == "不整形" else 0.0)
        - (0.25 if shape == "袋地" else 0.0)
        - 0.08 * (1 if road_type == PRIVATE_ROAD else 0)
        + random.gauss(0, 0.08)
    )
    return int(math.exp(base + eff))


def gen_mlit():
    rows = []
    for i in range(60):  # 直近1年フィルタ後でも30件以上残るよう増やす
        district = random.choice(DISTRICTS)
        area = round(random.uniform(50, 300), 0)
        walk = random.randint(3, 15)
        shape = random.choices(SHAPES, weights=SHAPE_W)[0]
        road_type = random.choices(ROAD_TYPES, weights=ROAD_W)[0]
        road_width = round(random.uniform(4.0, 10.0), 1)
        road_dir = random.choice(ROAD_DIRS)
        year, quarter = random.choice(QUARTERS)
        kanguchi = round(random.uniform(4.0, 15.0), 1)
        unit_price = gen_unit_price(area, walk, shape, road_type, road_dir, kanguchi, road_width)
        total_price = int(unit_price * area)
        # 取引価格は通常100万円単位丸め
        total_price = (total_price // 1_000_000) * 1_000_000

        row = {
            "種類": "宅地(土地)",
            "地域": "住宅地",
            "市区町村コード": "13103",
            "都道府県名": "東京都",
            "市区町村名": "港区",
            "地区名": district,
            "最寄駅:名称": STATIONS[district],
            "最寄駅:距離(分)": walk,
            "取引価格(総額)": total_price,
            "坪単価": "",
            "間取り": "",
            "面積(㎡)": int(area),
            "取引価格(㎡単価)": int(total_price / area),
            "土地の形状": shape,
            "間口": kanguchi,
            "延床面積(㎡)": "",
            "建築年": "",
            "建物の構造": "",
            "用途": "住宅",
            "今後の利用目的": "住宅",
            "前面道路:方位": road_dir,
            "前面道路:種類": road_type,
            "前面道路:幅員(m)": road_width,
            "都市計画": "第一種中高層住居専用地域",
            "建ぺい率(%)": 60,
            "容積率(%)": 200,
            "取引時点": f"{year}年第{quarter}四半期",
            "改装": "",
            "取引の事情等": "",
        }
        rows.append(row)
    return rows


def gen_koji():
    """公示地価(毎年1月1日時点)。同地区で過去3年分。"""
    base_unit_2023 = {"麻布十番": 4_500_000, "赤坂": 4_200_000, "白金": 3_800_000}
    rows = []
    for district, base in base_unit_2023.items():
        for year, growth in [(2023, 1.00), (2024, 1.04), (2025, 1.07)]:
            rows.append({
                "標準地番号": f"港-{district}-1",
                "都道府県名": "東京都",
                "市区町村名": "港区",
                "地区名": district,
                "価格時点": f"{year}-01-01",
                "価格(円/㎡)": int(base * growth),
                "用途": "住宅",
            })
    return rows


def gen_kijun():
    """基準地価(毎年7月1日時点)。同地区で過去3年分。"""
    base_unit_2023 = {"高輪": 3_900_000, "三田": 4_000_000}
    rows = []
    for district, base in base_unit_2023.items():
        for year, growth in [(2023, 1.00), (2024, 1.05), (2025, 1.08)]:
            rows.append({
                "基準地番号": f"港-{district}-1",
                "都道府県名": "東京都",
                "市区町村名": "港区",
                "地区名": district,
                "価格時点": f"{year}-07-01",
                "価格(円/㎡)": int(base * growth),
                "用途": "住宅",
            })
    return rows


def gen_property():
    """査定対象物件サンプル。"""
    return {
        "物件略号": "MIN001",
        "都道府県名": "東京都",
        "市区町村名": "港区",
        "地区名": "麻布十番",
        "面積(㎡)": 120,
        "最寄駅:名称": "麻布十番",
        "最寄駅:距離(分)": 7,
        "土地の形状": "整形",
        "間口": 8.0,
        "前面道路:方位": "南",
        "前面道路:種類": "公道",
        "前面道路:幅員(m)": 6.0,
        "都市計画": "第一種中高層住居専用地域",
        "建ぺい率(%)": 60,
        "容積率(%)": 200,
        "査定時点": "2026-05-01",
    }


def write_csv(path, rows):
    with open(path, "w", encoding="utf-8-sig", newline="") as f:
        writer = csv.DictWriter(f, fieldnames=list(rows[0].keys()))
        writer.writeheader()
        writer.writerows(rows)


if __name__ == "__main__":
    write_csv(HERE / "sample_mlit.csv", gen_mlit())
    write_csv(HERE / "sample_koji.csv", gen_koji())
    write_csv(HERE / "sample_kijun.csv", gen_kijun())
    with open(HERE / "sample_property.json", "w", encoding="utf-8") as f:
        json.dump(gen_property(), f, ensure_ascii=False, indent=2)
    print("Generated sample_mlit.csv (60 rows), sample_koji.csv, sample_kijun.csv, sample_property.json")

SHA-256: cfb757d386ee55b80571505d1967f7394636f93017bf9d2eaf65a7fe0d81dc62