3.1 回帰のユースケース

ブルックリン住宅データセットには、ブルックリン区内の住宅の販売価格に加え、住宅の面積、立地、住戸形式など、価格に影響を与える様々な要因が含まれています。あなたは、長年にわたる住宅販売の履歴データを分析して販売価格を試算よう求められており、これにより、不動産業務を最適化できます。このケース・スタディでは、回帰手法およびGLMアルゴリズムを使用して販売価格を予測する方法を学習します。

関連コンテンツ

トピック リンク
OML4Py GitHubの例 OML4Py回帰GLM
一般化線形モデルについて 一般化線形モデルとは
機械学習のクラスとアルゴリズムについて 機械学習のクラスとアルゴリズムについて
共有設定 共有設定
OML4Pyユースケースの探求を開始する前に、次の用意ができていることを確認します:

3.1.1 データのロード

データをデータベースにロードし、データセットとその属性を調べます。

「Rolling sales data」から、ブルックリン区のデータセットをダウンロードできます。Oracle Autonomous AI Databaseを使用している場合は、Oracle Cloud Infrastructure (OCI) Object Storageにファイルをアップロードし、サンプル表を作成し、OCI Object Storage上のファイルからサンプル表にデータをロードして、データを探索します。

データの調査

データセットには110個の属性があります。重要な属性をいくつか次に説明します。属性の詳細は、「Rolling sales data」を参照してください。

属性名 情報
Borough 課税対象区画が所在する区。
BoroCode 課税対象区画が所在する区。
Year Built 建物の建設が完了した年。
Zip Code 課税対象区画に割り当てられた住所のいずれかに対して有効な郵便番号。
Address 課税対象区画の住所
BUILDING CLASS 課税対象区画での建造物の主な用途を記述するコード。
HEALTH CENTER DISTRICT 課税対象区画が所在する医療センター区域。地域に根ざした保健介入を実施するために、市は1930年に30の医療センター区域を創設しました。
LAND USE CATEGORY 課税対象区画の土地利用カテゴリのコード
LOT AREA 課税対象区画の総面積(平方フィートで表し、最も近い整数に四捨五入)。
Building Area 総面積(平方フィート)。gross_sqftと同じです
Gross Square Feet 建物の外壁外側面から計測した全階の総面積(敷地内の土地および建物や建造物内部の空間を含む)。
Year Built 敷地内の建造物が建てられた年。
Sales Price 物件の購入価格

3.1.1.1 データのインポート

オブジェクト・ストレージ(クラウド用)を使用して、データをOracle AI Databaseにインポートします。

クラウド・アカウントを使用している場合、データのインポート方法の1つとしてオブジェクト・ストレージを使用します。データ・セットをオブジェクト・ストレージにアップロードします。オブジェクト・ストレージURIは、別のプロシージャで使用されます。Oracle AI Databaseツールやオラクル社およびサード・パーティ製のデータ統合ツールを使用して、Oracle Autonomous AI Database (Autonomous Data Warehouse [ADW]またはAutonomous Transaction Processing [ATP])にデータをロードできます。次のようにデータをロードできます。
  • クライアント・コンピュータのローカル・ファイルから、または
  • クラウドベースのオブジェクト・ストアに格納されているファイルから

データ・ファイルをオブジェクト・ストレージ・バケットにアップロードするステップに従います。

  1. クラウド・アカウントにログインします。
  2. 左側のハンバーガ・メニューをクリックし、メニューから「ストレージ」を選択します。
  3. 「オブジェクト・ストレージおよびアーカイブ・ストレージ」オプションから「バケット」を選択します。
  4. データをアップロードするコンパートメントを選択します。
  5. 「バケットの作成」をクリックします。
  6. バケットの名前を入力します。たとえば、Bucket1です。残りのフィールドはデフォルトのままにします。
  7. 「作成」をクリックします。
  8. 作成したバケットをクリックします。下にスクロールし、「オブジェクト」の下の「アップロード」をクリックします。
  9. 「オブジェクト名接頭辞」フィールドは空白のままにします。「ファイルを選択」をクリックして、アップロードするデータ・ファイルに移動するか、データ・ファイルをドラッグ・アンド・ドロップします。このユースケースでは、変更された.csvファイルを選択します。
  10. 「アップロード」をクリックします。データ・ファイルが「オブジェクト」の下に表示されます。
  11. データ・ファイルの右側にある省略記号をクリックしてメニューを表示します。「オブジェクト詳細の表示」をクリックします。
  12. URL PATH (URI)をテキスト・ファイルにコピーします。このURIは、DBMS_CLOUD.COPY_DATAプロシージャで使用されます。

このプロシージャでは、クラウド・アカウントにデータ・ファイルが格納されるオブジェクト・ストレージを作成します。

認証トークンの作成

認証トークンは、DBMS_CLOUD.CREATE_CREDENTIALプロシージャで必要です。クラウド・アカウントで認証トークンを生成できます。

  1. ADW Cloudアカウントにログインします。
  2. コンソールの右上隅の人間の形をしたアイコンの上にマウス・カーソルを置き、ドロップダウン・メニューから「ユーザー設定」をクリックします。
  3. コンソール左側にある「リソース」で認証トークンをクリックします。
  4. 「トークンの生成」をクリックします。ポップアップ・ダイアログが表示されます。
  5. 説明を入力します(オプション)。
  6. 「トークンの生成」をクリックします。
  7. 生成されたトークンをテキスト・ファイルにコピーします。トークンは表示されなくなります。
  8. 「閉じる」をクリックします。

オブジェクト・ストレージ資格証明の作成

オブジェクト・ストレージ資格証明は、DBMS_CLOUD.COPY_DATAプロシージャで使用されます。

  1. OML Notebooksページにログインして、ノートブックを作成します。「ノートブック・クラシックの作成」を参照してください
  2. 作成したばかりのノートブックを開きます。
  3. 次の問合せを入力してオブジェクト・ストレージ資格証明を作成します。
    %script
    begin
      DBMS_CLOUD.create_credential (
        credential_name => 'CRED',
        username => '<your cloud account username>',
        password => '<your Auth Token>'
      );
    end;
    /
    ---------------------------  PL/SQL procedure successfully completed.
        ---------------------------

    問合せを詳しく見てみます:

    • credential_name: 格納する資格証明の名前。任意の名前を指定します。ここで、CREDは指定された名前です。
    • username: これは、クラウド・アカウントのユーザー名です。
    • password: 認証トークンの生成後にコピーした認証トークンのパスワードを入力します。
  4. 再生アイコンをクリックして、ノートブック内の問合せを実行します。資格証明はADWユーザー・スキーマに格納されます。
  5. 別のパラグラフで、次の問合せを実行してユーザー資格証明を確認します。
    SELECT* FROM USER_CREDENTIALS;

3.1.2 データの探索

データを調べ、データの品質を理解して評価します。このステージでは、データを評価してデータ内のデータ型およびノイズを識別します。欠損値および数値外れ値を探します。

データの理解と準備

このステージでは、次のステップを通してデータセットを明確に理解することに重点を置きます:

  • 必要なライブラリのインポート: Oracle Machine Learning (OML)とともに必須Pythonライブラリをロードします。
  • データセットのロード: 初期探索のためにデータセットをインポートします。
  • DataFrameプロキシ・オブジェクトの作成: プロキシ・オブジェクトを使用して表を表し、データ操作を簡略化します。
  • 初期分析の実行: データセットの構造(形状、データ型、欠損値、質的特徴のカーディナリティなど)を調べます。

これらのステップは、より深いデータの探索および前処理のための強固な基盤となります。

データの準備および理解のために、次のステップを実行します:

  1. 必要なライブラリのインポート

    %pythonインタプリタ・パラグラフで次のスクリプトを実行して、omlモジュール、Pandaのモジュールをインポートし、表示オプションを設定します:
    
    import oml
    import ssl
    import pandas as pd
    import numpy as np
    import matplotlib.pyplot as plt
    
    import warnings
    warnings.simplefilter(action='ignore', category=FutureWarning)
  2. データセットのロード

    
    url="https://objectstorage.us-ashburn-1.oraclecloud.com/n/adwc4pm/b/OML_Data/o/brooklyn_sales.csv"
    ssl._create_default_https_context = ssl._create_unverified_context
    brooklyn_sales = pd.read_csv(url, engine='python')
    z.show(brooklyn_sales.head())

    図3-1 ブルックリンのRAWデータ


    このスクリーンショットは、ブルックリンのRAWデータセットの最初の数行を示しています。データは未処理で、IDやboroughなどの様々な属性が含まれています。

  3. 欠損値の置換(NaNをNoneに置換)

    
    df = brooklyn_sales.apply(lambda x: x.replace(np.nan, None) if x.dtypes == 'object' else x)
  4. データ型に基づいた欠損値の補完

    このコードはまず、完全に空であるか、欠損値のみを含む列を削除します。次に、残りの各列を調べて、非欠損値のデータ型をチェックし、列の型に基づいて最も適切な置換値で欠損データを埋めます。
     
    # Drop columns where all values are missing
    brooklyn_sales1 = brooklyn_sales.dropna(axis=1, how="all")
    
    d = {}
    
    # Iterate through each column and fill missing values based on its data type
    for col in brooklyn_sales1:
        x = brooklyn_sales1[col].dropna().tolist()  # Get non-null values to check the column type
        
        if len(x) > 0:  
            # For text columns, replace missing values with an empty string
            if isinstance(x[0], str):
                y = brooklyn_sales1[col].fillna("")
            # For integer columns, missing values are left unchanged
            elif isinstance(x[0], int):
                y = brooklyn_sales1[col]
            # For other numeric columns (e.g., floats), replace missing values with 0.0
            else:
                y = brooklyn_sales1[col].fillna(float(0))
            
            d[col] = y  # Store the modified column
    
    # Convert the dictionary back into a DataFrame
    brooklyn_sales2 = pd.DataFrame.from_dict(d)
    
    # Print the shape of the updated DataFrame
    print(brooklyn_sales2.shape)
    (390883, 110)
  5. DataFrameプロキシ・オブジェクトの作成

    
    try:
        oml.drop(table = 'BROOKLYN')
    except:
        pass
    
    # Create a persistent table named BROOKLYN in the Oracle AI
                                    Database
    BROOKLYN = oml.create(brooklyn_sales2, table="BROOKLYN")
  6. DataFrameの分析

    形状、データ型、欠損値を調査して解釈し、カーディナリティが低い列を見つけます。
    • DataFrameの形状:
      BROOKLYN.shape
      (390883, 110)
    • 列のデータ型:
      BROOKLYN.dtypes
      ID                         <class 'oml.core.integer.Integer'>
      borough                    <class 'oml.core.integer.Integer'>
      neighborhood                 <class 'oml.core.string.String'>
      building_class_category      <class 'oml.core.string.String'>
      tax_class                    <class 'oml.core.string.String'>
                                                ...                
      PFIRM15_FL                     <class 'oml.core.float.Float'>
      Version                      <class 'oml.core.string.String'>
      MAPPLUTO_F                     <class 'oml.core.float.Float'>
      SHAPE_Leng                     <class 'oml.core.float.Float'>
      SHAPE_Area                     <class 'oml.core.float.Float'>
      Length: 110, dtype: object
    • 欠損値を含む列(>75%)の特定:
      
      def percent_missing(dat):
          per_miss={}
          large_miss_columns=[]
          for i in dat.columns:
              l=len(dat)
              a=100-(dat[i].count()/l)*100
              if a>=75:
                  per_miss[i]=round(a)
          return per_miss
          
      z.show(pd.DataFrame(list(percent_missing(BROOKLYN).items()), columns=["Columns", "% Missing"]))

      図3-2 列とその欠損率の表示


      このスクリーンショットは、欠損値が75%以上含まれている列を示しています。

    • カーディナリティが低い列の特定:
      
      def unique_values_less_10(data):
          cols=[]
          for x in data.columns:
              unique_values=data[x].nunique()
              if  unique_values< 10:
                  cols.append(x)
          return cols
      
      print(unique_values_less_10(BROOKLYN)) 
      ['borough', 'tax_class_at_sale', 'Borough', 'SanitBoro', 'ZoneDist4', 'Overlay1', 'Overlay2',
            'SPDist2', 'SPDist3', 'LtdHeight', 'SplitZone', 'Easements', 'OwnerType', 'AreaSource', 'Ext',
            'ProxCode', 'IrrLotCode', 'BsmtCode', 'BoroCode', 'CondoNo', 'ZMCode', 'PLUTOMapID',
            'FIRM07_FLA', 'PFIRM15_FL', 'Version', 'MAPPLUTO_F']

3.1.2.1 データ準備

データ準備は、機械学習アルゴリズムとの互換性を高めるために、RAWデータのクリーニング(欠損値、外れ値および不整合の処理)、変換(スケーリング、エンコーディングおよび新しい特徴の作成)および編成を実行するプロセスです。

データ準備

このステージでは、次のステップを通してデータセットを明確に理解することに重点を置きます:

  • 冗長列:
    • データのクリーニング: 重複レコード、冗長列および相関性の高い列を特定して削除します。
  • データ・サブセットの作成: 関連する列をフィルタ処理または選択します。
  • 可視化: データ・パターンおよび関係を理解するためのビジュアル表現を生成します。
  • 特徴エンジニアリング: "建築年代"、"売却時の築年数"、"所在地住所"などの新しい特徴を作成します。
  • DataFrameのクリーニング: 欠損値、外れ値および不整合を処理します。
  • DataFrameの次元: クリーニング後に次元が適正か確認します。

これらのステップは、データ準備のための強固な基盤となります。

冗長列: データのクリーン・アップ

冗長列を特定するために、手がかりを求めて列名と説明を比較します。次に、列内のデータを分析して、値が同一であったり、高い相関関係にあるかどうかを確認します。冗長列を特定したら、削除する列を決定する必要があります。欠損値が多い列、不整合な書式の列、大部分が一意の値を持つ列は削除できます。

類似したネーミング規則を持つ列の分析

内容またはネーミング規則や書式設定の違いによって類似しているように見える列のペアまたはグループを分析および比較します。目標は、データ整合性を確保し、冗長性を検出し、列が同じ情報を表しているかどうかを確認することです。

比較される列は次のとおりです:

  • borough、Borough、BoroCode
  • YearBuiltとyear_built
  • ZipCodeとzip_code

同様に、他の列(building_class、BldgClass、building_class_at_saleやAddressとaddressなど)にも適用できます。

  1. 列の比較: borough、Borough、BoroCode

    列名"borough"、"Borough"、"BoroCode"はよく似ており、同じ情報が含まれている可能性を示唆しています。これを確認するために、比較用に各列からランダムに5つのサンプルを出力します。さらに、列の説明に基づくと、3つの列はすべてブルックリン区を表しており、"BK"や"3.0"などの値が含まれています。データはブルックリンに固有であるため、これらの列は冗長であり、データセットから削除しても問題ありません。

    
    z.show(BROOKLYN[['borough','Borough', 'BoroCode']].sample(n=5))

    列borough、Borough、BoroCodeからのサンプル・データで、ランダムに5つの行が表示されています。

  2. データの一致率の特定

    def matching_percentage(data, cols, threshold=0.9):
        # Filter rows where both columns have non-zero values
        filtered_df = data[(data[cols[0]] != 0) & (data[cols[1]] != 0)]
        
        # Calculate matching percentage
        total_rows = len(filtered_df)
        matching_rows = len(filtered_df[filtered_df[cols[0]] == filtered_df[cols[1]]])
        matching_percentage = matching_rows / total_rows if total_rows else 0
        
        # Output result
        if matching_percentage >= threshold:
            print(f"The columns have a high percentage ({matching_percentage * 100:.2f}%) of matching values, suggesting similarity.")
        else:
            print("The columns do not have a high percentage of matching values.")
  3. 列の比較: YearBuiltとyear_built

    列名"YearBuilt"と"year_built"はよく似ており、同じ情報が含まれている可能性を示唆しています。これを確認するために、各列からランダムに5つのサンプルを出力します。

    
    matching_percentage(BROOKLYN, ['YearBuilt', 'year_built'])
    The columns have a high percentage (99.25%) of matching values, suggesting
    similarity.

    列"YearBuilt"、"year_built"には同様の情報が含まれているため、一方を削除します。"year_built"をデータセットからを削除します。

  4. 列の比較: ZipCodeとzip_code

    
    matching_percentage(BROOKLYN, ['ZipCode', 'zip_code'])
    The columns have a high percentage (98.72%) of matching values, suggesting
    similarity.

    列名"ZipCode"と"zip_code"はよく似ており、同じ情報が含まれている可能性を示唆しています。これを確認するために、各列からランダムに5つのサンプルを出力します。

    
    z.show(BROOKLYN[['ZipCode', 'zip_code']].sample(n=5))

    列ZipCodeとzip_codeからのサンプル・データで、ランダムに5つの行が示されています。

必要な列を選択してデータをフィルタ処理

より信頼性の高いデータに的を絞るために、1800年代以降に建てられた住宅のみがデータセットに含まれています。これは、1800年代より前に建てられた住宅では、YearBuiltが多くの場合、一律の値0になっており、情報が欠落しているか不正確である可能性を示しているためです。詳細は、次のステップで説明します。

BROOKLYN2 = BROOKLYN[(BROOKLYN['YearBuilt']>= 1800)][['building_class_at_sale', 'HealthCent', 'YearBuilt', 'ResidFAR', 
'sale_date', 'building_class_category', 'GarageArea', 'CD', 'YearAlter1', 'ID', 'SchoolDist', 'SanitDistr', 'PolicePrct','address',
'CT2010', 'commercial_units', 'BldgArea','NumFloors', 'sale_price','AssessTot', 'ResArea','land_sqft','LotFront', 
'LotArea','AssessLand', 'SHAPE_Area','year_of_sale', 'gross_sqft','XCoord','YCoord', 'SHAPE_Leng']]

# Dataframe dimension
BROOKLYN2.shape
(295356, 31)

特徴エンジニアリングと可視化

可視化から得られたインサイトに基づいて、新しい列を作成して既存の特徴を変更します。その後、新しくエンジニアリングされた特徴がデータセットにマージされ、データセットの品質が高まり、モデリングの準備が強化されます。

  1. 建築時期とその件数:

    • 住宅が建てられた時期の分布を分析し、データセット内で出現頻度が最も低い時期と最も高い時期を特定します。列YearBuiltはまず、最も近い整数値に四捨五入されます。その後、これらの端数処理された値は、事前定義済の間隔(ビン)に分類されます。各ビン内のYearBuiltの数をカウントして、建築時期の頻度分布を割り出します。

      built_period = (BROOKLYN2['YearBuilt'] // 10) * 10 + oml.Integer(BROOKLYN2['YearBuilt'] % 10 >= 5) * 10
      bins_str = built_period.cut(bins=[1700,1800,1880,1900,1920,1940,1960,1980,2000,2020,2040])
      bins = sorted(bins_str.drop_duplicates().pull())
       
      z.show(pd.DataFrame({'Built Period':bins, 'Count':[oml.Integer(bins_str == b).sum() for b in bins]}))

      列"建築時期"のカテゴリ出現回数。

    • 建築時期とその件数の可視化

      # Data might be incomplete when DECADE_BUILT < 1900
       
      Nbins = 141
      n, bins, patches = plt.hist(built_period.pull(), Nbins)
      plt.xlabel('Built_Period')
      plt.ylabel('number of records')
      plt.yscale('log')
      p = plt.xlim(1795, 2025)

      列"建築時期"のカテゴリ出現回数の図。

  2. ビニングによる販売価格および件数のプレビュー

    • 住宅の販売価格の分布を分析し、データセット内で出現頻度が最も低い販売価格と最も高い販売価格を特定します。列sale_priceは四捨五入された後、事前定義済の間隔(ビン)に分類されます。各ビン内のsale_priceの数をカウントして、sale_priceの頻度分布を割り出します。

      Sale_Price=(BROOKLYN2['sale_price'].cut(bins=[-100000000,0,20000,40000,60000,80000,100000,1000000,10000000,500000000]))
      
      # bins_str = decade_built.cut(bins=[1700,1800,1880,1900,1920,1940,1960,1980,2000,2020,2040])
      bins = sorted(Sale_Price.drop_duplicates().pull())
       
      z.show(pd.DataFrame({'Sale Price':bins, 'Count':[oml.Integer(Sale_Price == b).sum() for b in bins]})) 

      この列は、列"販売期間"の出現回数を示しています。

    • 対数販売価格分布の調査

      
      # Most properties have 10^5 < sale_price < 10^6.5=3.2M
      Nbins = 101
      
      n, bins, patches = plt.hist((BROOKLYN2[BROOKLYN2['sale_price']>0]['sale_price']).log(10).pull(), Nbins)
      plt.xlabel('log10(sale_price)')
      plt.ylabel('number of records')
      p = plt.xlim(3.9, 7.1)

      この図は、列"販売価格"の出現回数を示しています。

  3. 建物区分カテゴリ、件数および件数の割合のプレビュー

    クロス集計を計算して、質的列building_class_categoryを分析します。この表を降順にソートします。最後に、各建物区分カテゴリの頻度を割り出します。

    build_category= BROOKLYN2.crosstab('building_class_category').sort_values('count', ascending=False)
    count_percentage= ((build_category['count'] / len(BROOKLYN2)) * 100).round(decimals=2)
    z.show(build_category.concat({'count_percentage':count_percentage}))

    この図は、各カテゴリの出現回数を示しています。

  4. 対数総平方フィート分布の調査

    列"総平方フィート"の値は、対数変換すると正規分布に近似します。

    # Most properties have 10^2.9=800 < sale_price < 10^3.7=5000
    Nbins = 201
    
    n, bins, patches = plt.hist((BROOKLYN2[BROOKLYN2['gross_sqft']>0]['gross_sqft']).log(10).pull(), Nbins)
    plt.xlabel('log10(sale_price)')
    plt.ylabel('number of records')
    p = plt.xlim(2.5, 4.2)

    対数総平方フィート分布を示しています

特徴エンジニアリング

特徴エンジニアリングは、既存のデータから新しい入力特徴を作成するプロセスであり、データの基礎となるパターンを説明します。これらの新しい特徴は、モデルの予測可能性を向上させるのに役立ちます。

エンジニアリングされている特徴は次のとおりです:

  • Built Period: 住宅が建てられた時期。
    built_period=(BROOKLYN2['YearBuilt'] // 10) * 10 + oml.Integer(BROOKLYN2['YearBuilt'] % 10 >= 5) * 10
    BROOKLYN2=BROOKLYN2.concat({'Built_Period':built_period})
  • Age_At_Sale: 売却時の住宅の築年数は、建築日から売却日までの年数です。
    Age_At_Sale2  = abs(BROOKLYN2['year_of_sale'] - BROOKLYN2['YearBuilt'])
    BROOKLYN2= BROOKLYN2.concat({'Age_At_Sale2': Age_At_Sale2})
  • Quarter: 住宅が建てられた四半期を指します。
    time_period = oml.Datetime.strptime(BROOKLYN2['sale_date'], format="MM/DD/YYYY")
    Quarter= (oml.Integer((time_period.month - 1)// 3 + 1))

DataFrameのクリーニング

特徴エンジニアリング後、分析に関与しなくなった列を削除し、欠損値を含む行をすべて削除します。

BROOKLYN2=BROOKLYN2.drop(['sale_date'])
BROOKLYN2=BROOKLYN2.dropna()

販売価格、総平方フィートおよび建築年代が特定の関連範囲内に収まる物件が含まれるように、データをフィルタ処理します。

BROOKLYN3 = BROOKLYN2[(BROOKLYN2['sale_price']>=1.0e5) & (BROOKLYN2['sale_price']<=5.0e6) & 
            (BROOKLYN2['gross_sqft']>=800) & (BROOKLYN2['gross_sqft']<=5000) & 
            (BROOKLYN2['Built_Period']>=1900) & (BROOKLYN2['Built_Period']<=2010) ]

対数変換を適用して列を正規化します。その後、変換前の元の列は削除されます。

BROOKLYN3 = BROOKLYN3.concat({'log_gross_sqft': BROOKLYN3['gross_sqft'].log(10)})
BROOKLYN3=BROOKLYN3.drop(['gross_sqft'])

モデルのパフォーマンスを向上させるには、特定の建物区分およびカテゴリに属する確率が高い物件に的を絞るように、データをフィルタ処理します。

BROOKLYN4 = BROOKLYN3[(BROOKLYN3['building_class_at_sale']=='A1') | (BROOKLYN3['building_class_at_sale']=='A2') 
            | (BROOKLYN3['building_class_at_sale']=='A4') | (BROOKLYN3['building_class_at_sale']=='A5') 
            | (BROOKLYN3['building_class_at_sale']=='B1') | (BROOKLYN3['building_class_at_sale']=='B2') 
            |  (BROOKLYN3['building_class_at_sale']=='B3') ]
BROOKLYN5 = BROOKLYN4[((BROOKLYN4['building_class_category']=='02 TWO FAMILY HOMES') | (BROOKLYN4['building_class_category']=='01 ONE FAMILY HOMES'))]

DataFrameの次元

次のスクリプトを実行して、DataFrameの次元を確認します:

BROOKLYN5.shape
(67083, 32)

3.1.3 モデルの構築

トレーニング・データ・セットを使用してモデルを構築します。oml.glm関数を使用してモデルを構築し、モデル設定を指定します。

回帰などの教師あり学習の場合は、モデルを作成する前にデータをトレーニング・データとテスト・データに分割します。データ・セット全体を使用してモデルを構築することはできますが、使用可能な新しいデータ・セットがないかぎり、モデルの検証は困難です。したがって、モデルを評価し、同じデータに対するモデルのパフォーマンスを正確に査定するには、通常、データをトレーニング・データとテスト・データに分割(分離)します。トレーニング・データ・セットを使用してモデルをトレーニングした後、テスト・データ・セットを使用して予測問合せを実行し、モデルの精度をテストします。テスト・データ・セットには、予測する属性の既知の値がすでに含まれています。したがって、モデルの予測が正しいかどうかを簡単に判断できます。

アルゴリズムの選択

モデルを構築する前に、適切なアルゴリズムを選択します。次のアルゴリズムのいずれかを選択して、回帰の問題を解決できます。

  • Extreme Gradient Boosting
  • 一般化線形モデル
  • ニューラル・ネットワーク
  • サポート・ベクター・マシン

データ・セットを理解する場合は、常に単純で簡単なベースライン・モデルから始めます。一般化線形モデル・アルゴリズムは、特徴とターゲット間の線形関係に適合するので単純で簡単に解釈できるため、適切な選択です。線形モデルの結果から新しいデータ・セットの最初の理解を得ることができます。

次のステップでは、データを分割し、選択したアルゴリズムを使用してモデルを構築する方法について説明します。

  1. データの分割: トレーニング/テスト:

    データをトレーニング・データとテスト・データに、それぞれ80対20の比率で分割します。seedパラメータは、ランダム分割に使用されます。splitメソッドは、DataFrameプロキシ・オブジェクトBROOKLYN5によって参照されるデータを2つの新しいDataFrameプロキシ・オブジェクト(trainとtest)に分割します。
    TRAIN, TEST = BROOKLYN5.split(ratio = (0.8,0.2), seed=15)
    TRAIN_X = TRAIN.drop('sale_price')
    TRAIN_Y = TRAIN['sale_price']
    TEST_X = TEST
    TEST_Y = TEST['sale_price']
  2. モデル構築:

    モデル設定を指定し、sale_price属性を予測するための一般化線形モデル(GLM)モデル・オブジェクトを構築するには、次のスクリプトを実行します。設定は、キーと値またはディクショナリのペアとして指定し、それぞれパラメータ名と値の設定を指しています。

    try:
        oml.drop(model = 'BROOKLYN_GLM_REGRESSION_MODEL')
    except:
        print('No such model')
     
    setting = {'PREP_AUTO':'ON',
               'GLMS_ROW_DIAGNOSTICS':'GLMS_ROW_DIAG_ENABLE',
               'GLMS_FTR_SELECTION':'GLMS_FTR_SELECTION_ENABLE',
               'GLMS_FTR_GENERATION':'GLMS_FTR_GENERATION_ENABLE'}
                
    glm_mod = oml.glm("regression", **setting)
    glm_mod = glm_mod.fit(TRAIN_X,TRAIN_Y,model_name = 'BROOKLYN_GLM_REGRESSION_MODEL',case_id = 'ID')
    

    モデル設定のパラメータ:

    • PREP_AUTO: 完全自動データ準備またはユーザーが指示する一般的なデータ準備を指定するために使用します。デフォルトでは、定数値'PREP_AUTO': PREP_AUTO_ONで有効になっています。
    • GLMS_ROW_DIAGNOSTICS: 行診断を有効または無効にします。デフォルトでは、行診断は無効になっています。
    • GLMS_FTR_SELECTION: GLMの特徴選択を有効または無効にします。デフォルトでは、特徴選択は無効です。
    • GLMS_FTR_GENERATION: GLMに対して特徴生成が有効になっているかどうかを指定します。デフォルトでは、特徴生成は有効化されていません。

      ノート:

      特徴生成は、特徴選択が有効な場合にのみ有効です。

3.1.4 評価

新しいデータでモデルを使用して予測を行う前に、まずモデルの精度を評価する必要があります。モデルは、様々な方法を使用して評価できます。

モデル設定に関する情報

モデルの構築後に生成された様々な統計を調べて、モデルを評価します。統計はモデルの品質を示します。

  • モデル詳細: GLMモデル・オブジェクトで使用可能なモデル詳細(モデル設定、属性係数、適合詳細など)を確認するために、次のスクリプトを実行します。
    glm_mod

    次に示すように、個別に表示して確認することもできます。

  • 属性係数: 次のスクリプトを実行して、モデルの属性係数を表示します。
    z.show(glm_mod.coef.round(2).head())

    属性係数を示しています。

  • 適合詳細: 次のスクリプトを実行して、モデルの適合詳細を表示します。
    z.show(glm_mod.fit_details.round(2).head())

    適合詳細を示しています。

スコア

スコアリングは、モデルをテスト・データに適用してそのパフォーマンスを評価するプロセスです

  1. 販売価格の予測: モデルを使用して、テスト・データに対して予測を行います。
    BROOKLYN_RES = glm_mod.predict(TEST.drop('sale_price'), supplemental_cols = TEST[:,['ID','sale_price']])
    z.show(BROOKLYN_RES.round(2).head())

    適合詳細を示しています

  2. モデルのパフォーマンスの評価: スコア機能を使用してモデルのパフォーマンスを評価します。
    model_coef = len(glm_mod.coef)
    no_rows_test = TEST_X.shape[0]
    R_squared = glm_mod.score(TEST_X, TEST_Y).round(3)
    
    print(
        f"RMSE : {(((BROOKLYN_RES['PREDICTION'] - BROOKLYN_RES['sale_price']) ** 2).mean() ** .5).round(2)}\n"
        f"MAE: {((abs(BROOKLYN_RES['PREDICTION'] - BROOKLYN_RES['sale_price'])).mean()).round(2)}\n"
        f"R squared: {R_squared}\n"
        f"Adjusted R^2: {(1 - ( 1 - R_squared)*(no_rows_test-1)/(no_rows_test - model_coef -1)).round(4)}"
    )

    メトリックに基づいたモデルのパフォーマンスの解釈は、次のとおりです:

    • RMSE (286,137.56): モデルの予測は、平均して実際の値から約286,137.56単位乖離しています。
    • MAE (170,992.05): 予測における平均絶対誤差は170,992.05単位であり、大きな誤差にペナルティを課すことなくモデルの精度を理解できます。
    • (0.581): モデルは、目的変数の分散の58.1%を説明しており、データに対して中程度の適合を示唆しています。
    • 調整済R²(0.5604): 予測子の数を調整した後では、モデルは分散の約56.04%を説明しています。

    全体として、モデルは中程度の予測精度を示し、さらに改善する余地があります。

  3. 残差グラフ: 残差プロットは、不均一分散パターンを示しています。これは、モデルの誤差に一貫性がないことを示します。適合値(予測値)と残差の間に見られる非線形の関係は、モデルをさらに改善できることを示唆しています。
    import matplotlib.pyplot as plt
     
    y_pred = BROOKLYN_RES['PREDICTION'].pull()
    residuals = (BROOKLYN_RES['sale_price'] - BROOKLYN_RES['PREDICTION']).pull()
     
    plt.scatter(y_pred, residuals)
     
    plt.xlabel('Predicted Sale Prices')
    plt.ylabel('Residuals')
    plt.title('Residual Plot', fontsize=16)
    plt.grid(True)
    plt.axhline(y=0, color='r', linestyle='--')
    plt.show()

    残差グラフの図

データをスコアリングして予測詳細を表示するためのSQLインタフェース

SQLインタフェースを使用して、データのスコアリングおよび予測を行うことができます。テスト・データはBROOKLYN_GLM_TEST_DATAにマテリアライズされるため、SQLを使用して問い合せることができます。マテリアライズ・メソッドは、Oracle Machine Learningのoml.DataFrameプロキシ表の内容をOracle AI Database表に書き込みます。

  1. 次の問合せで使用するためにBROOKLYN_GLM_TEST_DATAをマテリアライズします:
    try:
        oml.drop(table = 'BROOKLYN_GLM_TEST_DATA')
    except:
        pass
    _ = TEST.materialize(table = 'BROOKLYN_GLM_TEST_DATA')
  2. SQLでの説明的な予測詳細を伴う予測の表示: スコアリングと予測詳細の表示を実行するSQLコマンド。予測関数は、BROOKLYN_GLM_REGRESSION_MODELという名前のGLM回帰モデルをマテリアライズされた表BROOKLYN_GLM_TEST_DATAのデータに適用します。この問合せには、予測に最も影響する予測子の情報が含まれています。

    SELECT ID,
           round(PREDICTION_YRS_RES,3) PRED_YRS_RES,
           round(PRED_LOWER_LIMIT,1) LOWER_BOUND,
           round(PRED_UPPER_LIMIT,1) UPPER_BOUND,
           RTRIM(TRIM(SUBSTR(OUTPRED."Attribute1",17,100)),'rank="1"/>') FIRST_ATTRIBUTE,
           RTRIM(TRIM(SUBSTR(OUTPRED."Attribute2",17,100)),'rank="2"/>') SECOND_ATTRIBUTE,
           RTRIM(TRIM(SUBSTR(OUTPRED."Attribute3",17,100)),'rank="3"/>') THIRD_ATTRIBUTE
    FROM (SELECT ID,
                 PREDICTION(BROOKLYN_GLM_REGRESSION_MODEL USING *) PREDICTION_YRS_RES,
                 PREDICTION_BOUNDS(BROOKLYN_GLM_REGRESSION_MODEL USING *).LOWER PRED_LOWER_LIMIT,
                 PREDICTION_BOUNDS(BROOKLYN_GLM_REGRESSION_MODEL USING *).UPPER PRED_UPPER_LIMIT,
                 PREDICTION_DETAILS(BROOKLYN_GLM_REGRESSION_MODEL USING *) PD
          FROM BROOKLYN_GLM_TEST_DATA
          WHERE ID < 100015
          ORDER BY ID) OUT,
         XMLTABLE('/Details'
                  PASSING OUT.PD
                  COLUMNS 
                  "Attribute1" XMLType PATH 'Attribute[1]',
                  "Attribute2" XMLType PATH 'Attribute[2]',
                   "Attribute3" XMLType PATH 'Attribute[3]') OUTPRED

    SQLで説明的な予測詳細とともに予測を表示しています

結論として、一般化線形モデル・アルゴリズムを使用してブルックリンの中間住宅価格を予測することに成功しました。