建物名を使って用途を当てようとするAI

はじめに

データクオリティーマネージャーのkageyuです。毎日建物の情報や募集の情報を確認しています。2万棟の建物の用途を95%以上の精度で用意する仕事があり、力技で何とかしたことがあります。私は力技が好きなのですが、「全部私が確認しました」だけが正解ではありません。今回は技術を使ったらどうなるのかの記事です。

建物名と用途

住居・オフィス・商業施設・公共施設・工場など、建物には色んな用途があります。estieは様々なプロダクトを展開しており、「estie マーケット調査」ではオフィスビルの情報が、「estie 物流リサーチ」には物流不動産の情報がまとまっています。オフィスと物流の性質は大きく違うため、例えばオフィスビルの情報を知りたいときに物流施設のデータが混じると調査に悪影響が出てしまいます。そのため、建物の情報からどのプロダクトに必要なデータなのかを判断する必要があります。

建物のデータにはそもそも用途の情報が入っていることもありますし、面積が狭ければ住居やシェアオフィスだろう、天井の高さや耐荷重が大きければ物流施設だろうと予想がつくこともあります。しかし今回はあえて名称のみを使って用途を当てようとする記事です。

ルールベース

建物名に「ホテル」が入っていればホテルだろうなどの単純なif文を書きます。

  • 「オフィス」が入っていればオフィス
  • 「ショッピング」や「プラザ」が入っていれば商業
  • 「ハウス」や「カーサ」が入っていれば住居
  • 「物流」が入っていれば物流
  • 「ホテル」が入っていればホテル
  • 「パーキング」が入っていればその他(駐車場)

など、頻出パターンを約10分かけていろいろ書いたところ、正答率は0.90になりました。ちなみにf1-scoreは0.89でした。

モデル 正答率 f1-score
if文 0.90 0.89

ちなみに使っているデータはJ-REITの建物5000棟分に私がラベル付けしたデータを使っています。オフィスが50%、住居が30%、商業・物流・ホテル・その他が各5%程度と偏りのあるデータです。

n-gramを使った判定

ルールベースでは、私が「建物名に「ホテル」が入ってる建物の用途はホテルだろう」と知識を直接教えていましたが、私が気がつかない単語もたくさんあると思います。この知識の発見も計算機に行わせます。

今回はn-gram(今回は連続する3~6文字)を使ったランダムフォレストで予測させてみました。イメージとしては下記のプログラムですが実際にはもっと書いて実行しています。

import csv
import pandas as pd

from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.ensemble import RandomForestClassifier
from sklearn.model_selection import train_test_split
from sklearn.metrics import classification_report

df = pd.read_csv('buildings.csv')
X = df['建物名']
y = df['用途']

# 特徴量変換
vectorizer = TfidfVectorizer(analyzer='char', ngram_range=(3,6))
X_vec = vectorizer.fit_transform(X)

# 分割と学習
X_train, X_test, y_train, y_test = train_test_split(X_vec, y, test_size=0.2, random_state=42)
clf = RandomForestClassifier()
clf.fit(X_train, y_train)

# 評価
y_pred = clf.predict(X_test)

正答率は0.90、f1-scoreが0.90でした。単なるn-gramでも精度が高く、ランダムフォレストのすごさを感じます。

モデル 正答率 f1-score
if文 0.90 0.89
n-gram + RF 0.90 0.90

間違った例を見ると、商業施設の「ダイエー宝塚中山店」をオフィスだと予測しています。n-gramを3~6文字にしたため1文字の「店」を学習できてなさそうです。またオフィスの「オーバルコート大崎マークウエスト」を住居だと予測したりしています。「コート」が住居っぽいからでしょう。

用途を当てるのに使ったn-gramは下記の表です。不自然な(単語として成立しない)n-gramがたくさん出ています。「イオンモール」や「レジディア」に含まれるn-gramが強く、用途毎の有名ブランドが大きな影響を与えていそうです。J-REITの判別器としては正しい知識を得ていそうです。

オフィス 商業 住居 物流 ホテル その他
1 町ビル イオン レジデ glp ホテル ーミー
2 田ビル モール レジディ ロジス ステイ ドーミー
3 橋ビル イオンモー ジディ センタ テルマ ドーミ
4 ルディ オンモー ジディア センター ホテルマイス ストップ
5 ルディング イオンモール レジディア ンター ホテルマイ ストッ

RandomForestClassifierclass_weight='balanced'を使って用途毎のレコード数の偏りは補正をしましたが、用途内のブランドの偏りも激しそうです。「ドーミー」はホテルだと思いますが謎です。

形態素解析とWord2vec

n-gramを使ったところ、「ルディ(ビルディングの一部)」や「オンモー(イオンモールの一部)」など、不自然な場所で切られた単語が見られます。形態素解析した方が適切な場所で単語として区切れて、精度が上がると思いました。さらにWord2vecを使えば「オフィス」と「事務所」が近い意味である事なども使えて精度が上がると思いました。コードのイメージも載せておきます。

import pandas as pd
import numpy as np
from janome.tokenizer import Tokenizer
from sklearn.ensemble import RandomForestClassifier
from sklearn.model_selection import train_test_split
from sklearn.metrics import classification_report
import fasttext

ft_model = fasttext.load_model('cc.ja.300.bin')
df = pd.read_csv('buildings.csv')

tokenizer = Tokenizer()

def text_to_vector(text):
    tokens = [token.surface for token in tokenizer.tokenize(text) if len(token.surface) >= 1]

    if not tokens:
        return np.zeros(300)

    vectors = []
    for token in tokens:
        vector = ft_model.get_word_vector(token)
        vectors.append(vector)

    return np.mean(vectors, axis=0)

X = np.array([text_to_vector(name) for name in df['建物名']])
y = df['用途'].values

X_train, X_test, y_train, y_test = train_test_split(
    X, y, test_size=0.2, random_state=42, stratify=y
)

# 学習
clf = RandomForestClassifier(random_state=42, class_weight='balanced', n_estimators=200)
clf.fit(X_train, y_train)

y_pred = clf.predict(X_test)

判断材料にした単語のランキングがいい感じで、精度も期待できそうです。

オフィス 商業 住居 物流 ホテル その他
1 ビル モール ハイツ 物流 ホテル プラザ
2 オフィス プラザ レジデンス センター タワー ホテル
3 ビルディング 百貨店 マンション 商業 プラザ ハイツ
4 本社 デパート タワー 商業 観光 マンション
5 タワー ビル プラザ 本社 商業 センター
モデル 正答率 f1-score
if文 0.90 0.89
n-gram + RF 0.90 0.90
Word2vec + RF 0.78 0.77

正答率は0.78、f1-scoreが0.77と下がっています。一般語彙の知識よりも、「レジディア」や「GLP」などの一般的な語彙ではない建物固有のブランド名のn-gramが用途判別に有用なのでしょうか…。J-REITのデータにはブランド名がよく付くため、運用会社の名前などが強く影響したJ-REIT特有の結果かも知れません。

Chat GPTに全てをお任せする

何も考えずにChat GPTに建物名を渡してその用途を聞いてみましょう。GPT 4oの検索なしで頼んだところ、正答率は73%でした。思ったより「オフィスっぽい」などのネーミングセンスは持ち合わせていないんですね…。変数名を相談していた範囲ではネーミングセンスがありそうな気がしていたのに。

モデル 正答率 f1-score
if文 0.90 0.89
n-gram + RF 0.90 0.90
Word2vec + RF 0.79 0.77
GPT-4o(検索なし) 0.73 0.77

物流施設の「IIF盛岡ロジスティクスセンター」をオフィスに分類しているなど、用途が明確な建物も間違えています。「さっきのコードを一瞬で出力してくれる人工知能なら、建物名から用途を類推するタスクだって軽々とやってくれるはず!」と思ったのですが意外と難しいんでしょうか。そもそもこんなベンチマークがないから能力がないのか、私の聞き方「下記の建物名に対して、用途(オフィス・商業・住居・物流・ホテル・その他)を当てて下さい。」が悪かったのか…

と思ってるうちにGPT-5が使えるようになったのでGPT-5でも試してみました。検索無しだと正答率が大きく下がってしまいましたが検索有りだと0.84で少し取り返しています。(if文に負けてるのは納得いかない。)

モデル 正答率 f1-score
if文 0.90 0.89
n-gram + RF 0.90 0.90
Word2vec + RF 0.79 0.77
GPT-4o(検索なし) 0.73 0.77
GPT-5(検索なし) 0.49 0.52
GPT-5(検索あり) 0.84 0.82

ちなみにestieの社員に聞いたところ、先頭100件の正解率は80%, 75%, 69%, 59%でした。(これもif文に負けてるのは納得いかない。)

Human-In-The-Loop

estieでは、AIの補助を受けながらも人間がチェックして用途を記入・修正しているので安心して下さい。人間の判断が確実ではないとはいえ、定期的にサンプリングを行い今回の実験の結果のどれよりも高い精度で提供できているはずです(95%信頼区間)。

建物の用途は建物単位で決められるとは限りません。例えば現在estieが入居しているミッドタウン・イーストも複雑で、入居している中層階はオフィスだけど地下は商業施設、そして高層階は住居です。建物によってはオフィスとしても店舗としても使っていい空室もあり、建物の用途の正解に悩むことも多いです。本実験では筆者の独断で用途を決めましたが、GPT-5が間違えた16件の多くは「ネットワークセンターはオフィスに含めるか?」「老人ホームは住居に含めるか?」などの判断に迷う建物でした。

(追記)
読者のコメントを受けてプロンプトを工夫したところ、精度が向上しました。個人的には「GPT-5には全てよしなに実行して欲しい~」と思っていましたが、GPT-5と私の判断が食い違う場所を、「老人ホームや寮は住居とは区別したいのでその他にして下さい。ネットワークセンターもオフィスとは区別したいのでその他にして下さい」などと頼むと、GPT-5の精度は0.90まで上がりました。頼んだ内容は判別結果を見て考えた物なので100棟に沿いすぎたパッチかもしれませんが、GPT-5が用途を間違えた建物は正解ラベル作りで私が用途の判断に迷った物が増え、if文を使ったルールベースの判別が間違えた建物と比べて明らかな間違いは減りましたし、GPTは「その他」としながらもserior_residentialなどともう少し情報をつけてくれている点も使えそうです。

最後に

看板の写真から入居者の名前をデータ化するタスクや、営業マンが残した手書きメモから空室情報を構造化するタスクなど、estieではAIを活用した効率化が色んな場所で行われています。

そんな課題にデータサイエンスやエンジニアリングの力で真っ向から挑みたい人を、私たちは探しています。「AIを活用して社会に価値を出す」仕事にワクワクするなら、ぜひestieの採用情報をご覧ください。私たちは、AIを活用する技術力を持っている仲間を歓迎します。AIの速度は私を超えましたが、出力の質はまだまだなので、AIの出力をチェックし続ける気合いを持つ人も歓迎します(特に私が)。

hrmos.co

hrmos.co

© 2019- estie, inc.