統計モデル(一般化線形モデル)に未知のデータを当てはめて予測値を出力すると有り得ない値になってしまいます。 (交差検証:cross variation)
解決済
回答 2
投稿
- 評価
- クリップ 0
- VIEW 307
前提・実現したいこと
Python、統計学初心者の者です。
仕事の関係で、下記のことをPythonで実現したいと考えております。
① あるデータをtrainデータとtestデータに分割する
② trainデータを用いて、GLM(一般化線形モデル)によるポアソン回帰モデルを作成する。
③ 上記のモデルにtestデータを代入し、testデータの実測値とモデルによる予測値を比較する
(交差検証:cross variation)
発生している問題・エラーメッセージ
まず、お弁当の需要予測(https://signate.jp/competitions/24)のデータを用いて、
上記の手法をトライしました。
Python初心者で思い通りのコードを書くことはできないので、
インターネットからコードのコピペを組み合わせて試行錯誤しました。
(https://tanuhack.com/statsmodels-multiple-lra/ を参考にしました。)
全データの半分をtrainデータ、半分をtestデータとしました。
気温を説明変数、お弁当の販売数を応答変数とするポアソン回帰モデルを作成しました。
すると③において、モデルによる予測値(Pred)が、eの50乗などと有り得ない数値となってしまいます。
コードに誤りがあれば教えて頂ければ幸甚です。
(出力結果のスクリーンショットを添付しております。)
該当のソースコード
# 1. 必要なライブラリの読み込み
import pandas as pd
import statsmodels.formula.api as smf
import statsmodels.api as sm
from matplotlib import pyplot as plt
# 2. 使用するデータの読み込み
df = pd.read_csv("Desktop/Pyhton memo/trainmoji.csv", encoding="shift-jis")
df.head()
train = df[0:len(df)//2]
test = df.drop(train.index)
# 3. smf.glmで使うformula(線形予測子)とfamily(確率分布)を設定する
trainY = train['y'] # 目的変数:y
trainX = pd.get_dummies(train[[
'temperature']]) # 説明変数
family = sm.families.Poisson()
trainX = sm.add_constant(trainX)
# 4. 先ほどの設定値を使って一般化線形モデルを作成
model = sm.GLM(trainY, trainX, family=family)
# 5. 作成したモデルを学習させる
result = model.fit()
# 6. 結果の表示
result.summary()
# 7. テストデータにモデルを当てはめて予測値を出力
testX = pd.get_dummies(test[['temperature']]) # 説明変数
testX['const'] = 1.0
pred = result.predict(testX)
test['pred'] = pred
test
補足情報(FW/ツールのバージョンなど)
-
気になる質問をクリップする
クリップした質問は、後からいつでもマイページで確認できます。
またクリップした質問に回答があった際、通知やメールを受け取ることができます。
クリップを取り消します
-
良い質問の評価を上げる
以下のような質問は評価を上げましょう
- 質問内容が明確
- 自分も答えを知りたい
- 質問者以外のユーザにも役立つ
評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。
質問の評価を上げたことを取り消します
-
評価を下げられる数の上限に達しました
評価を下げることができません
- 1日5回まで評価を下げられます
- 1日に1ユーザに対して2回まで評価を下げられます
質問の評価を下げる
teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。
- プログラミングに関係のない質問
- やってほしいことだけを記載した丸投げの質問
- 問題・課題が含まれていない質問
- 意図的に内容が抹消された質問
- 過去に投稿した質問と同じ内容の質問
- 広告と受け取られるような投稿
評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。
質問の評価を下げたことを取り消します
この機能は開放されていません
評価を下げる条件を満たしてません
質問の評価を下げる機能の利用条件
この機能を利用するためには、以下の事項を行う必要があります。
- 質問回答など一定の行動
-
メールアドレスの認証
メールアドレスの認証
-
質問評価に関するヘルプページの閲覧
質問評価に関するヘルプページの閲覧
checkベストアンサー
+1
解説を書こうと思ったのですが、ここに、ほぼ答えに近い内容が書かれていましたので、参考になるかと思います。
投稿
-
回答の評価を上げる
以下のような回答は評価を上げましょう
- 正しい回答
- わかりやすい回答
- ためになる回答
評価が高い回答ほどページの上位に表示されます。
-
回答の評価を下げる
下記のような回答は推奨されていません。
- 間違っている回答
- 質問の回答になっていない投稿
- スパムや攻撃的な表現を用いた投稿
評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。
+1
データの内容がわからないので、多少憶測になりますがコメントします。
1.pd.get_dummies()について
説明変数に気温を使いたいということですが、気温は通常連続値です。get_dummies()はカテゴリーデータをダミー変数に変換するためのものなので、使用する関数が違うのではないでしょうか。仮にそのまま連続値のまま説明変数として使いたいのであれば、このコードは不要です。
なお、このままget_dummiesを使う場合、記載を以下のしないと変換しません。
pd.get_dummies(train['temperature'])
2.ポアソン回帰を使う場合の約束事
ポアソン分布の期待値はマイナスを取ることはありません。よって期待値を計算するモデルの核になる部分(a×気温+b)は必ずマイナスにならないようにする必要があります。これをリンク関数と呼びますが、今のコードにはリンク関数の考慮がありません。このあたりをいちいち実装するのは面倒なので、たいていはkeisuke0919さんが紹介するサイトを参考に実装を改めたほうがいいでしょう。
3.結果がおかしな理由
一番致命的な部分はポアソン回帰の約束事が実装されていないことのように思われます。ただ、その前に気温という連続値をどのように扱いたいのかをご自身で意識しないと思ったようになりません。
加えていうと、お弁当販売数が気温によって決定される、という仮説が可視化を通じて確認できていないとやはり思った結果にはなりません。
投稿
-
回答の評価を上げる
以下のような回答は評価を上げましょう
- 正しい回答
- わかりやすい回答
- ためになる回答
評価が高い回答ほどページの上位に表示されます。
-
回答の評価を下げる
下記のような回答は推奨されていません。
- 間違っている回答
- 質問の回答になっていない投稿
- スパムや攻撃的な表現を用いた投稿
評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。
15分調べてもわからないことは、teratailで質問しよう!
- ただいまの回答率 88.35%
- 質問をまとめることで、思考を整理して素早く解決
- テンプレート機能で、簡単に質問をまとめられる
2020/07/11 07:43
ご添付頂いたサイトには、GLMを用いてポアソン回帰モデルを作成するところまで記載されております。
ポアソン回帰モデルの作成は既に成功しているのですが、未知のデータをそのモデルに当てはめて予測値を出すところで行き詰っております。
質問に添付したスクリーンショットのように、どうしてもPredの値が桁違いに大きくなってしまうのですが、コードのどこを修正すれば良いかご教授頂けるとありがたいです。
よろしくお願い申し上げます。
2020/07/11 14:17 編集
結論としては、
In[2]の
testX['const'] = 1.0
を
testX = sm.add_constant(testX)
に書き換えましょう。
そうすると適切な予測になりました。
2020/07/11 14:20
モデルが想定するデータと異なってしまいます。
testX = sm.add_constant(testX)とすることで、左側にconstカラムを持ってくることができます。学習に用いたデータ(trainX)の形に合わせたと言うことです。
2020/07/12 10:35
keisuke0919様の仰る通りに書き換えたところ、適切な予測となりました。
これで仕事に役立てることができそうです。
親身に御返答頂きありがとうございました。
2020/07/12 14:23