概要
このチュートリアルでは、野菜の相場データに対して
- データの読み込み
- データの確認と前処理
- Lasso回帰による回帰モデルの作成、学習
- 提出用データの作成
を行います。
import pandas as pd
import numpy as np
import sklearn
!python3 --version
print(pd.__version__)
print(np.__version__)
print(sklearn.__version__)
import matplotlib
print(matplotlib.__version__)
Python 3.7.7
1.1.5
1.19.4
0.21.3
3.1.3
データのロード
まずはデータを読みます。
csvデータの読み込みは一般的によく使われるpandas
のread_csv
関数が機能が豊富なため利用します。
csvデータについて、pandas.DataFrame
として返してくれます。
import pandas as pd
train_data = pd.read_csv("train_data.csv", index_col='id')
print(train_data.shape)
(47, 340)
また、DataFrame
には.head()
というメソッドが定義されており、これを呼び出すとDataFrame
の先頭の数行を確認できます。
train_data.head()
|
えのきだけ_中国 |
えのきだけ_九州 |
えのきだけ_北海道 |
えのきだけ_北陸 |
えのきだけ_四国 |
えのきだけ_東北 |
えのきだけ_東海 |
えのきだけ_近畿 |
えのきだけ_関東 |
かぶ_北海道 |
... |
レタス_関東 |
生しいたけ_中国 |
生しいたけ_九州 |
生しいたけ_北海道 |
生しいたけ_北陸 |
生しいたけ_四国 |
生しいたけ_東北 |
生しいたけ_東海 |
生しいたけ_近畿 |
生しいたけ_関東 |
id |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2016-01-01 |
314.0 |
301.0 |
304.0 |
274.0 |
267.0 |
213.0 |
278.0 |
285.0 |
279.0 |
124.0 |
... |
271.0 |
1098.0 |
1048.0 |
737.0 |
1231.0 |
1021.0 |
988.0 |
1119.0 |
1113.0 |
1118.0 |
2016-02-01 |
306.0 |
316.0 |
309.0 |
288.0 |
293.0 |
278.0 |
286.0 |
295.0 |
291.0 |
157.0 |
... |
311.0 |
1080.0 |
956.0 |
750.0 |
1241.0 |
1037.0 |
964.0 |
1139.0 |
1127.0 |
1116.0 |
2016-03-01 |
245.0 |
217.0 |
317.0 |
219.0 |
227.0 |
164.0 |
210.0 |
213.0 |
204.0 |
185.0 |
... |
278.0 |
946.0 |
739.0 |
728.0 |
1202.0 |
886.0 |
941.0 |
989.0 |
937.0 |
1044.0 |
2016-04-01 |
227.0 |
182.0 |
304.0 |
195.0 |
202.0 |
153.0 |
205.0 |
203.0 |
189.0 |
189.0 |
... |
209.0 |
875.0 |
749.0 |
734.0 |
1014.0 |
827.0 |
887.0 |
924.0 |
882.0 |
982.0 |
2016-05-01 |
232.0 |
202.0 |
306.0 |
206.0 |
215.0 |
170.0 |
221.0 |
220.0 |
206.0 |
150.0 |
... |
165.0 |
886.0 |
821.0 |
710.0 |
1055.0 |
892.0 |
867.0 |
942.0 |
946.0 |
990.0 |
5 rows × 340 columns
同様に天候情報についてもデータを読み込みます。
weather = pd.read_csv('weather.csv', index_col=0, header=[0,1,2])
print(weather.shape)
(59, 5967)
weather.head()
|
宗谷 |
... |
沖縄 |
|
稚内 |
... |
南大東(南大東島) |
|
平均気温(℃) |
日平均気温25℃以上日数(日) |
日最高気温の平均(℃) |
日平均気温0℃未満日数(日) |
日最低気温の平均(℃) |
日最高気温25℃以上日数(日) |
最高気温(℃) |
日最高気温0℃未満日数(日) |
最低気温(℃) |
日最低気温25℃以上日数(日) |
... |
日最高気温0℃未満日数(日) |
最低気温(℃) |
日最低気温25℃以上日数(日) |
日最低気温0℃未満日数(日) |
降水量の合計(mm) |
日降水量の最大(mm) |
最深積雪(cm) |
降雪量合計(cm) |
日照時間(時間) |
日照時間0.1時間未満日数(日) |
年月 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2015/1 |
-2.9 |
0.0 |
-1.1 |
28.0 |
-5.0 |
0.0 |
4.3 |
19.0 |
-8.1 |
0.0 |
... |
0.0 |
7.3 |
0.0 |
0.0 |
42.0 |
14.5 |
0.0 |
0.0 |
99.8 |
5.0 |
2015/2 |
-1.7 |
0.0 |
0.2 |
21.0 |
-4.0 |
0.0 |
5.3 |
14.0 |
-11.0 |
0.0 |
... |
0.0 |
5.8 |
0.0 |
0.0 |
7.0 |
4.5 |
0.0 |
0.0 |
126.7 |
1.0 |
2015/3 |
2.3 |
0.0 |
4.4 |
4.0 |
0.1 |
0.0 |
10.0 |
0.0 |
-5.2 |
0.0 |
... |
0.0 |
10.1 |
0.0 |
0.0 |
26.0 |
10.5 |
0.0 |
0.0 |
178.0 |
2.0 |
2015/4 |
5.9 |
0.0 |
8.9 |
0.0 |
3.1 |
0.0 |
15.7 |
0.0 |
-2.0 |
0.0 |
... |
0.0 |
11.8 |
0.0 |
0.0 |
120.0 |
36.0 |
0.0 |
0.0 |
171.2 |
1.0 |
2015/5 |
9.9 |
0.0 |
13.1 |
0.0 |
7.1 |
0.0 |
18.8 |
0.0 |
2.9 |
0.0 |
... |
0.0 |
16.2 |
8.0 |
0.0 |
313.5 |
166.0 |
0.0 |
0.0 |
210.0 |
1.0 |
5 rows × 5967 columns
天候情報については2015年1月分のデータから存在するようです。
毎月1日の地域ごとの野菜の価格がデータにまとめられていることがわかります。
データの確認と前処理
訓練データの各品目の価格分布について確認します。
train_data.describe()
|
えのきだけ_中国 |
えのきだけ_九州 |
えのきだけ_北海道 |
えのきだけ_北陸 |
えのきだけ_四国 |
えのきだけ_東北 |
えのきだけ_東海 |
えのきだけ_近畿 |
えのきだけ_関東 |
かぶ_北海道 |
... |
レタス_関東 |
生しいたけ_中国 |
生しいたけ_九州 |
生しいたけ_北海道 |
生しいたけ_北陸 |
生しいたけ_四国 |
生しいたけ_東北 |
生しいたけ_東海 |
生しいたけ_近畿 |
生しいたけ_関東 |
count |
47.000000 |
47.000000 |
47.000000 |
47.000000 |
47.000000 |
47.000000 |
47.000000 |
47.000000 |
47.000000 |
47.000000 |
... |
47.000000 |
47.000000 |
47.000000 |
47.000000 |
47.000000 |
47.000000 |
47.000000 |
47.000000 |
47.000000 |
47.000000 |
mean |
251.425532 |
235.574468 |
284.723404 |
230.659574 |
240.829787 |
179.957447 |
239.872340 |
232.978723 |
223.744681 |
156.638298 |
... |
208.936170 |
898.936170 |
857.808511 |
684.914894 |
1019.872340 |
896.361702 |
859.489362 |
951.404255 |
938.106383 |
995.234043 |
std |
55.707990 |
63.407497 |
22.070738 |
55.274523 |
55.517455 |
66.101686 |
55.335584 |
57.252868 |
58.983221 |
37.791433 |
... |
95.682538 |
118.526534 |
156.466782 |
57.738101 |
126.364486 |
115.511420 |
92.727247 |
120.762192 |
125.053421 |
97.040380 |
min |
166.000000 |
119.000000 |
237.000000 |
152.000000 |
151.000000 |
77.000000 |
150.000000 |
143.000000 |
128.000000 |
96.000000 |
... |
110.000000 |
718.000000 |
624.000000 |
525.000000 |
759.000000 |
721.000000 |
686.000000 |
780.000000 |
748.000000 |
859.000000 |
25% |
207.000000 |
180.500000 |
269.000000 |
192.500000 |
203.000000 |
135.500000 |
203.500000 |
185.500000 |
174.500000 |
135.000000 |
... |
148.000000 |
805.000000 |
732.000000 |
637.500000 |
929.500000 |
794.000000 |
793.500000 |
853.000000 |
829.000000 |
914.000000 |
50% |
246.000000 |
228.000000 |
287.000000 |
218.000000 |
230.000000 |
168.000000 |
223.000000 |
220.000000 |
208.000000 |
152.000000 |
... |
174.000000 |
889.000000 |
821.000000 |
686.000000 |
1017.000000 |
883.000000 |
847.000000 |
942.000000 |
932.000000 |
979.000000 |
75% |
293.000000 |
287.500000 |
301.000000 |
263.500000 |
272.500000 |
230.000000 |
276.000000 |
274.500000 |
268.000000 |
167.500000 |
... |
230.500000 |
989.500000 |
1004.000000 |
731.000000 |
1112.500000 |
994.000000 |
943.000000 |
1033.500000 |
1043.500000 |
1073.000000 |
max |
388.000000 |
384.000000 |
331.000000 |
372.000000 |
383.000000 |
330.000000 |
382.000000 |
365.000000 |
364.000000 |
286.000000 |
... |
550.000000 |
1160.000000 |
1251.000000 |
801.000000 |
1247.000000 |
1188.000000 |
1029.000000 |
1265.000000 |
1251.000000 |
1225.000000 |
8 rows × 340 columns
stdが各カラムにおける標準偏差であり、この値が大きいほど価格が大きく変動していることになります。品目毎に値動きの大きさは変わります。
また、同じ品目でも地域ごとに価格の安定した地域、不安定な地域があることが確認できました。産地からの距離が運送に影響を与えていたり、消費地域の需要の高低といった要因によって、価格の安定性に影響が出ていると考えられます。
set(weather.columns) - set(weather.dropna(axis=1).columns)
{('三重', '上野', '最深積雪(cm)'),
('三重', '上野', '降雪量合計(cm)'),
('三重', '四日市', '最深積雪(cm)'),
('三重', '四日市', '降雪量合計(cm)'),
('三重', '尾鷲', '最深積雪(cm)'),
('三重', '尾鷲', '降雪量合計(cm)'),
('兵庫', '兎和野高原', '最深積雪(cm)'),
('兵庫', '兎和野高原', '降雪量合計(cm)'),
('兵庫', '姫路', '最深積雪(cm)'),
('兵庫', '姫路', '降雪量合計(cm)'),
('兵庫', '洲本', '最深積雪(cm)'),
('兵庫', '洲本', '降雪量合計(cm)'),
('千葉', '勝浦', '最深積雪(cm)'),
('千葉', '勝浦', '降雪量合計(cm)'),
('千葉', '千葉', '最深積雪(cm)'),
('千葉', '千葉', '降雪量合計(cm)'),
('千葉', '館山', '最深積雪(cm)'),
('千葉', '館山', '降雪量合計(cm)'),
('和歌山', '潮岬', '最深積雪(cm)'),
('和歌山', '潮岬', '降雪量合計(cm)'),
('大分', '日田', '最深積雪(cm)'),
('大分', '日田', '降雪量合計(cm)'),
('宮崎', '延岡', '最深積雪(cm)'),
('宮崎', '延岡', '降雪量合計(cm)'),
('宮崎', '油津', '最深積雪(cm)'),
('宮崎', '油津', '降雪量合計(cm)'),
('宮崎', '都城', '最深積雪(cm)'),
('宮崎', '都城', '降雪量合計(cm)'),
('山口', '萩', '最深積雪(cm)'),
('山口', '萩', '降雪量合計(cm)'),
('島根', '浜田', '最深積雪(cm)'),
('島根', '浜田', '降雪量合計(cm)'),
('広島', '呉', '最深積雪(cm)'),
('広島', '呉', '降雪量合計(cm)'),
('広島', '福山', '最深積雪(cm)'),
('広島', '福山', '降雪量合計(cm)'),
('愛媛', '宇和島', '最深積雪(cm)'),
('愛媛', '宇和島', '降雪量合計(cm)'),
('愛知', '伊良湖', '最深積雪(cm)'),
('愛知', '伊良湖', '降雪量合計(cm)'),
('東京', '三宅島', '最深積雪(cm)'),
('東京', '三宅島', '降雪量合計(cm)'),
('東京', '八丈島', '最深積雪(cm)'),
('東京', '八丈島', '降雪量合計(cm)'),
('東京', '南鳥島', '最深積雪(cm)'),
('東京', '南鳥島', '降雪量合計(cm)'),
('東京', '大島', '最深積雪(cm)'),
('東京', '大島', '降雪量合計(cm)'),
('東京', '父島', '最深積雪(cm)'),
('東京', '父島', '降雪量合計(cm)'),
('沖縄', '与那国島', '最深積雪(cm)'),
('沖縄', '与那国島', '降雪量合計(cm)'),
('沖縄', '久米島', '最深積雪(cm)'),
('沖縄', '久米島', '降雪量合計(cm)'),
('沖縄', '名護', '最深積雪(cm)'),
('沖縄', '名護', '降雪量合計(cm)'),
('沖縄', '西表島', '最深積雪(cm)'),
('沖縄', '西表島', '降雪量合計(cm)'),
('熊本', '人吉', '最深積雪(cm)'),
('熊本', '人吉', '降雪量合計(cm)'),
('熊本', '牛深', '最深積雪(cm)'),
('熊本', '牛深', '降雪量合計(cm)'),
('福岡', '飯塚', '最深積雪(cm)'),
('福岡', '飯塚', '降雪量合計(cm)'),
('福島', '小名浜', '最深積雪(cm)'),
('福島', '小名浜', '降雪量合計(cm)'),
('長崎', '佐世保', '最深積雪(cm)'),
('長崎', '佐世保', '降雪量合計(cm)'),
('長崎', '厳原', '最深積雪(cm)'),
('長崎', '厳原', '降雪量合計(cm)'),
('長崎', '平戸', '最深積雪(cm)'),
('長崎', '平戸', '降雪量合計(cm)'),
('長崎', '福江', '最深積雪(cm)'),
('長崎', '福江', '降雪量合計(cm)'),
('長崎', '雲仙岳', '最深積雪(cm)'),
('長崎', '雲仙岳', '降雪量合計(cm)'),
('静岡', '三島', '最深積雪(cm)'),
('静岡', '三島', '降雪量合計(cm)'),
('静岡', '御前崎', '最深積雪(cm)'),
('静岡', '御前崎', '降雪量合計(cm)'),
('静岡', '浜松', '最深積雪(cm)'),
('静岡', '浜松', '降雪量合計(cm)'),
('静岡', '石廊崎', '最深積雪(cm)'),
('静岡', '石廊崎', '降雪量合計(cm)'),
('静岡', '網代', '最深積雪(cm)'),
('静岡', '網代', '降雪量合計(cm)'),
('香川', '多度津', '最深積雪(cm)'),
('香川', '多度津', '降雪量合計(cm)'),
('高知', '室戸岬', '最深積雪(cm)'),
('高知', '室戸岬', '降雪量合計(cm)'),
('高知', '宿毛', '最深積雪(cm)'),
('高知', '宿毛', '降雪量合計(cm)'),
('高知', '清水', '最深積雪(cm)'),
('高知', '清水', '降雪量合計(cm)'),
('鹿児島', '屋久島', '最深積雪(cm)'),
('鹿児島', '屋久島', '降雪量合計(cm)'),
('鹿児島', '枕崎', '最深積雪(cm)'),
('鹿児島', '枕崎', '降雪量合計(cm)'),
('鹿児島', '沖永良部', '最深積雪(cm)'),
('鹿児島', '沖永良部', '降雪量合計(cm)'),
('鹿児島', '種子島', '最深積雪(cm)'),
('鹿児島', '種子島', '降雪量合計(cm)'),
('鹿児島', '阿久根', '最深積雪(cm)'),
('鹿児島', '阿久根', '降雪量合計(cm)')}
非降雪地帯の降雪に関するカラムにはNaN
が含まれるようです。
予測モデルの作成、学習
モデルに投入する目的変数(y)と、説明変数(X)を作成します。
今回は前月の天候情報からある月の相場を予測します。
train_dataでは、月次の価格データが時系列で与えられるため、2か月以上前の農作物の価格や、その推移情報についても活用することが可能です。
X = weather.iloc[11:-1, :].fillna(0)
y = train_data
いよいよ予測モデルの作成に入ります。
model.fit('説明変数','目的変数')
とすることで、学習データを使用した回帰モデルを作成できます。
今回は、Lasso回帰と呼ばれる回帰手法を利用して予測をします。比較用に一般的な線形回帰モデルでも学習をしてみます。
import sklearn
from sklearn.linear_model import Lasso
from sklearn.linear_model import LinearRegression
Lasso = Lasso(max_iter=10000)
lr = LinearRegression()
Lasso.fit(X, y)
lr.fit(X, y)
モデルの評価
また、コンペの評価指標となるRMSLE
スコアを確認してみましょう。
今回は、sklearn.metrics
に含まれるmean_squared_error
メソッドを使用します。
0に近いほど予測精度が高いことを表します。
モデルを元にした予測値は、model.predict('説明変数')
で表します。
from sklearn.metrics import mean_squared_log_error
y_true = y
y_pred = lr.predict(X)
print(np.sqrt(mean_squared_log_error(y_true, y_pred)))
2.145828653485621e-15
今回作成したモデルのRMSLEは上記の通りでした。
テストデータに対する出力
最後に、作成したモデルを使用して将来の野菜価格を予測します。
test_data = weather.iloc[-1:, :].fillna(0)
test_data.head()
|
宗谷 |
... |
沖縄 |
|
稚内 |
... |
南大東(南大東島) |
|
平均気温(℃) |
日平均気温25℃以上日数(日) |
日最高気温の平均(℃) |
日平均気温0℃未満日数(日) |
日最低気温の平均(℃) |
日最高気温25℃以上日数(日) |
最高気温(℃) |
日最高気温0℃未満日数(日) |
最低気温(℃) |
日最低気温25℃以上日数(日) |
... |
日最高気温0℃未満日数(日) |
最低気温(℃) |
日最低気温25℃以上日数(日) |
日最低気温0℃未満日数(日) |
降水量の合計(mm) |
日降水量の最大(mm) |
最深積雪(cm) |
降雪量合計(cm) |
日照時間(時間) |
日照時間0.1時間未満日数(日) |
年月 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2019/11 |
2.6 |
0.0 |
5.3 |
10.0 |
-0.3 |
0.0 |
12.8 |
4.0 |
-7.3 |
0.0 |
... |
0.0 |
16.7 |
0.0 |
0.0 |
54.5 |
32.5 |
0.0 |
0.0 |
123.5 |
6.0 |
1 rows × 5967 columns
先ほど使用したmodel.predict('説明変数')
の説明変数
にテストデータの値を代入することで、テストデータの予測値を算出することができます。
下記のようにして、提出用のsubmission.csv
を出力することが可能です。
test_predicted = lr.predict(test_data)
submit_df = pd.DataFrame(test_predicted)
submit_df.columns = train_data.columns
submit_df = submit_df.transpose()
submit_df.index.name = 'id'
submit_df.columns = ['y']
submit_df.to_csv('submission.csv')
submit_df
id y
えのきだけ_中国 314.878998
えのきだけ_九州 288.642959
えのきだけ_北海道 282.941308
えのきだけ_北陸 279.403830
えのきだけ_四国 285.298373
... ...
生しいたけ_四国 1040.834107
生しいたけ_東北 975.056885
生しいたけ_東海 1124.099756
生しいたけ_近畿 1132.671180
生しいたけ_関東 1110.588409