こんにちは。三度の飯より不動産が大好きな桑原です。「Dify」と 「不動産情報ライブラリ」を利用し、特定地域の物件の相場単価を教えてくれるチャットボットを無料で作成してみました。今回はその作成方法をご紹介します。
チャットボットの完成イメージ
以下のような結果を出力するチャットボットの作成を目指します。
出力結果1
出力結果2
不動産情報ライブラリからデータを取得し、LLM(大規模言語モデル)を使って物件相場の単価を算出します。おまけで、今後の単価も予測してもらいましょう。
作成手順
1. 不動産情報ライブラリから物件データを取得
物件データの取得方法は2通りあります。いずれかの方法でお試しください。
対象方法さくっと試したい方Webサイトから物件データをダウンロードする踏み込んでみたい方APIを使って物件データを取得する
方法1:Webサイトから物件データをダウンロードする
不動産情報ライブラリのサイトにアクセスする下図のように知りたい地域の情報を選択し、データをダウンロードする。ダウンロード後のデータはExcelで開くことができます。なお、その場で結果を一覧表示することもできます。ダウンロードする前の確認に使ってください。
選択例
対象物件一覧表示
(任意)ダウンロードしたExcelから、必要な情報のみフィルタリングする。例えば対象物件を中古マンションのみ、かつ築年数を2015年以降のみにフィルタリングする等。
※高精度のLLMを利用すれば、物件の種類や築年数をうまく分類して相場単価を教えてくれえると思いますが、必要な情報のみLLMにINPUTする方が精度は期待できます。
方法2:APIを使ってデータを取得する
APIの利用申請を行う。承認が得られたらAPIのKEYが発行されるので控えてください。APIを使って物件データを取得する。以下のサンプルコードを参考にしてください。API_KEYには取得したご自身のAPI KEYを設定してください。
import requests
import pandas as pd
import argparse
import re
# APIアクセスとデータ制限の設定
API_KEY = "YOUR KEY"
BASE_URL = "https://www.reinfolib.mlit.go.jp/ex-api/external"
MIN_YEAR_AVAILABLE = 2005
# 都道府県名を対応するIDにマッピングする関数
def get_prefecture_id():
return {
'北海道': 1, '青森県': 2, '岩手県': 3, '宮城県': 4, '秋田県': 5, '山形県': 6, '福島県': 7,
'茨城県': 8, '栃木県': 9, '群馬県': 10, '埼玉県': 11, '千葉県': 12, '東京都': 13,
'神奈川県': 14, '新潟県': 15, '富山県': 16, '石川県': 17, '福井県': 18,
'山梨県': 19, '長野県': 20, '岐阜県': 21, '静岡県': 22, '愛知県': 23,
'三重県': 24, '滋賀県': 25, '京都府': 26, '大阪府': 27, '兵庫県': 28,
'奈良県': 29, '和歌山県': 30, '鳥取県': 31, '島根県': 32, '岡山県': 33,
'広島県': 34, '山口県': 35, '徳島県': 36, '香川県': 37, '愛媛県': 38,
'高知県': 39, '福岡県': 40, '佐賀県': 41, '長崎県': 42, '熊本県': 43,
'大分県': 44, '宮崎県': 45, '鹿児島県': 46, '沖縄県': 47
}
# 不動産APIへのリクエストを実行する関数
def make_api_request(endpoint, params):
try:
# APIエンドポイントの完全なURLを構築
response = requests.get(f"{BASE_URL}/{endpoint}",
headers={"Ocp-Apim-Subscription-Key": API_KEY},
params=params)
response.raise_for_status() # HTTPエラーの場合は例外を発生させる
return response.json()
except requests.RequestException as e:
print(f"APIリクエストエラー: {e}")
return None
# 都道府県(エリアコード)と市区町村名を使って市区町村コードを取得する関数
def get_city_code(area_code, city_name):
data = make_api_request("XIT002", {"area": area_code})
if data:
for entry in data.get('data', []):
if entry['name'] == city_name:
return entry['id']
return None # 市区町村コードが見つからなければNoneを返す
# 入力された期間を年のリストに変換する関数
def get_year_range(period):
start, end = (period.split('-') if '-' in period else (period, period))
years = list(range(int(start), int(end) + 1))
if min(years) < MIN_YEAR_AVAILABLE:
raise ValueError(f"エラー: 指定された期間が利用可能な最小年 {MIN_YEAR_AVAILABLE} よりも前です。")
return years
# 不動産データを取得して表示するメインの機能
def fetch_data(prefecture, city, period, district=None):
# 指定された都道府県と市区町村のIDを取得
area_code = get_prefecture_id().get(prefecture)
city_code = get_city_code(area_code, city)
if not city_code: # 市区町村コードが見つからない場合のチェック
print(f"{city} の市区町村コードが見つかりませんでした。")
return
combined_data = [] # 各年のデータフレームを保持するリスト
for year in get_year_range(period):
# 指定された期間内の各年のデータをリクエスト
data = make_api_request("XIT001", {"year": year, "area": area_code, "city": city_code})
if data and 'data' in data:
df = pd.DataFrame(data["data"]) # JSONデータをデータフレームに変換
if district: # 地区でのフィルタリングが指定された場合
df = df[df['DistrictName'] == district]
combined_data.append(df[df['Type'] == '中古マンション等']) # 中古マンション等でフィルタリング
if combined_data:
# 全てのデータフレームを連結し、表示用に処理
df_final = pd.concat(combined_data, ignore_index=True)
df_final['TradePrice'] = df_final['TradePrice'].apply(lambda x: f"{int(x):,}") # 取引価格をフォーマット
# 'BuildingYear' の処理を修正
def format_building_year(year):
if pd.isna(year):
return None
match = re.findall(r'(\d{4})', year) # すべての4桁の年を抽出
if match:
return "年, ".join(match) + "年" # 抽出された年を "YYYY年, YYYY年" の形式に結合
return year
df_final['BuildingYear'] = df_final['BuildingYear'].apply(format_building_year)
pd.set_option('display.max_rows', None) # pandasのオプションを設定し全行表示
print(df_final) # 最終的なデータフレームを出力
else:
print("指定されたクエリに利用可能なデータがありません。")
if __name__ == "__main__":
# コマンドライン入力のための引数パーサー
parser = argparse.ArgumentParser(description="不動産データ取得プログラム")
parser.add_argument("--prefecture", required=True, help="都道府県名 (例: '東京都')")
parser.add_argument("--city", required=True, help="市区町村名 (例: '港区')")
parser.add_argument("--district", help="絞り込む地区名 (例: '赤坂')")
parser.add_argument("--period", required=True, help="年または期間 (例: '2023' または '2016-2024')")
args = parser.parse_args()
# 引数で指定された条件に基づきデータを取得
fetch_data(args.prefecture, args.city, args.period, args.district)
$ python3 real_estate.py --prefecture="福岡県" --city="小倉北区" --district="金田" --period="2023-2024"
PriceCategory Type Region MunicipalityCode Prefecture Municipality DistrictName TradePrice PricePerUnit FloorPlan Area UnitPrice LandShape Frontage TotalFloorArea BuildingYear Structure Use Purpose Direction Classification Breadth CityPlanning CoverageRatio FloorAreaRatio Period Renovation Remarks
0 不動産取引価格情報 中古マンション等 40106 福岡県 北九州市小倉北区 金田 8,800,000 4DK 65 1980年 SRC 住宅 住宅 商業地域 80 400 2023年第2四半期 改装済み
1 不動産取引価格情報 中古マンション等 40106 福岡県 北九州市小倉北区 金田 9,800,000 4LDK 85 1991年 SRC 住宅 商業地域 80 400 2023年第2四半期 未改装
2 不動産取引価格情報 中古マンション等 40106 福岡県 北九州市小倉北区 金田 5,000,000 2DK 75 1991年 SRC 住宅 商業地域 80 400 2023年第2四半期 未改装
3 不動産取引価格情報 中古マンション等 40106 福岡県 北九州市小倉北区 金田 10,000,000 2LDK 75 1991年 SRC 住宅 住宅 商業地域 80 400 2023年第3四半期 未改装
4 不動産取引価格情報 中古マンション等 40106 福岡県 北九州市小倉北区 金田 29,000,000 3LDK 100 2006年 RC 住宅 住宅 商業地域 80 400 2023年第3四半期 未改装
5 不動産取引価格情報 中古マンション等 40106 福岡県 北九州市小倉北区 金田 39,000,000 3LDK 85 2019年 RC 住宅 住宅 商業地域 80 400 2023年第4四半期 未改装
2. Difyの実行環境を構築
こちらのブログを参考にしてください。ConoHa VPSを使ってコミュニティ版のDifyを構築する手順です。この手順の場合、Dify自体は無料ですが、VPSの利用料は発生します。しかし、Difyのコミュニティ版は、メモリ4GB以上の環境であれば動作可能なため、PC上でも構築できます。そうすれば無料ですね。
3. LLM接続用のAPIキーを取得
今回は 「Groq」のAPIを使います。レート制限内のリクエスト数であれば、無料で利用可能です。詳細は公式サイトよりご確認ください。
Groqの公式サイトにアクセスアカウント作成後、APIキー(SECRET KEY)を発行する
4. Dify上でLLM接続用のAPIキーを登録
構築したDifyにブラウザでログインする右上のアカウントメニュー → 設定
モバイルプロバイダー → モデルに「groqcloud」を選択 → セットアップ先ほど発行したGroqのAPIキーを入力して保存
5. Difyでチャットボットを作成
Difyのスタジオにて「最初から作成」→「チャットボット」を選択アプリに名前を付ける → 作成「手順」に以下のプロンプトを与える。
あなたは不動産業界のプロフェッショナルです。
以下に示す中古マンションの取引データに基づき、地域特性を考慮した詳細な分析を実施してください。
特に Prefecture, Municipality, DistrictName の情報を使用して、該当地域に関する人口推移や都市の発展状況を調査し、
未来予測に含めてください。
データ形式:
- TradePrice: 物件の売買成立価格(単位は円)
- Area: 物件の広さ(単位は平米)
- Period: 物件の売買が成立した年
- BuildingYear: 物件の建築年
- Prefecture, Municipality, DistrictName: 地域を特定する情報
分析手順:
1. 各物件の平米あたりの売買成立価格を年度ごとに計算し、地域(`Prefecture`, Municipality, DistrictName)ごとに集計する。
2. 地域ごとの年度別価格傾向を分析し、物件の築年数、状態、立地条件などの影響要因を検討する。
3. Prefecture, Municipality, DistrictName に基づいて、その地域の人口推移、都市計画、経済指標を強調し、これらが不動産市場に与える影響を評価する。
4. 未来のX年度の平米あたりの売買成立価格を予測する。この予測には、過去のデータだけでなく、地域経済の動向、人口動態などを考慮する。
5. 総合的な見解を示し、不動産市場の将来展望や区域に対応した投資戦略を提言する。
データ:
{{{input_data}}}}
このプロンプトにより、特定の地域に依存した分析と予測を実施し、信頼性の高い市場動向の把握を目指します。
変数キー「input_data」を定義する
変数「input_data」の歯車アイコンをクリックし、詳細設定画面を開く。フィールドタイプを「段落」、最大長(最大input文字数)を「20000」に設定する。最大長はLLMに依存します。エラーが出る際は調整してください。
右上のLLM選択ボックスから使用するLLMを選択する。Groq APIで接続可能なモデルが複数表示されるので、お好みのモデルを選択してください。今回は「DeepSeek R1」を使うことにします。
作成したアプリを保存する。右上の「公開する」→「更新」
6. チャットボットアプリを実行
不動産情報ライブラリから取得した物件データをコピペする。ベタ貼りでもLLMがうまく処理してくれると思いますが、今回はLLMが理解しやすいようにjson形式で渡します。チャット欄にて「start」と指示する。
利用するLLMによって差異はありますが、冒頭で紹介したような分析結果が得られるはずです。
まとめと今後の展望
いかがでしょうか?既に物件を所有している方は、得られた結果は妥当の範囲だったでしょうか?精度は利用するLLMやINPUTするデータの量など、様々な要因で変わると思います。結果はあくまで参考程度にし、むしろ作る工程を楽しんでいただければと思います。
なお、個人的には以下が現状の課題と考えており、今後改修しようと思っています。
不動産情報スクリプトとDifyの実行が分離している。Difyから一度に処理できるようにしたい。いま現在の将来予測はLLMが元々学習しているデータと、その学習期間に依存する。精度を上げるために、RAGで地域性の最新データを拡張検索させるようにしたい。