Browse Source

Fin predict script

Petra Lamborn 5 years ago
parent
commit
4d1f64c25c
1 changed files with 121 additions and 16 deletions
  1. 121
    16
      py/predict.py

+ 121
- 16
py/predict.py View File

@@ -6,38 +6,143 @@ import datetime as dt
6 6
 import pickle
7 7
 from pymodels import thirtyoffset, predweather, harmonic
8 8
 from pprint import pprint
9
+from util import datevalid
10
+from signal import signal, SIGPIPE, SIG_DFL
11
+
12
+def preddemand(model, weather, harmonics):
13
+    harmstart = thirtyoffset(weather.index.min())
14
+    utv = weather.index
15
+    harmlen = len(utv)
16
+
17
+    yharm = harmonic(harmlen, period=365.25 * 48, start=harmstart,
18
+                     harmonics=harmonics[0], prefix="y")
19
+    yharm.index = utv
20
+
21
+    wharm = harmonic(harmlen, period=7 * 48, start=harmstart,
22
+                     harmonics=harmonics[1], prefix="w")
23
+    wharm.index = utv
24
+
25
+    dharm = harmonic(harmlen, period=48, start=harmstart,
26
+                     harmonics=harmonics[2], prefix="d")
27
+    dharm.index = utv
28
+
29
+    df = p.concat([yharm, wharm, dharm, weather], axis = 1)
30
+    return model.predict(df)
9 31
 
10 32
 def main():
11 33
     parser = ArgumentParser(description=
12 34
                             'Predict from harmonic model of cluster')
13 35
     parser.add_argument("-m", "--model-file", dest="model_file",
14 36
                         help="filename for models",
15
-                        default="../models/testmod.pkl",
37
+                        required = True,
38
+                        type=FileType('rb'))
39
+    parser.add_argument("-w", "--weather",  dest="weather_file",
40
+                        help="input weather pickle path",
41
+                        required=False,
16 42
                         type=FileType('rb'))
17
-    # parser.add_argument("-w", "--weather",  dest="weather",
18
-    #                     help="input weather pickle path",
19
-    #                     metavar="PATH", required=True,
20
-    #                     type=FileType('rb'))
21
-    parser.add_argument("--weather-harmonics", dest="weather_harmonics",
22
-                        help="number of harmonics for weather; default: 2",
23
-                        type=int, default=2, metavar="NUM")
24
-    parser.add_argument("--icp-harmonics", dest="icp_harmonics", nargs=3,
25
-                        help="harmonics for icp fitting, default 2 3 3",
26
-                        default=[2, 3, 3], type=int,
27
-                        metavar="NUM")
43
+    parser.add_argument("-o", "--output", dest="output_file",
44
+                        help="file to save result",
45
+                        required=True, type=FileType('w'))
46
+    parser.add_argument("-t", "--temperature", dest="temp",
47
+                        help = "min and max temperature, if not using "
48
+                        "weather dataset, e.g. 2.0 10.5", 
49
+                        required=False,
50
+                        type=float, nargs=2)
51
+    parser.add_argument("-s", "--start-date", 
52
+                        dest = "startdate", 
53
+                        help = "start date for prediction; format: YYYY-MM-DD; default: 2018-01-01", 
54
+                        metavar="START_DATE", 
55
+                        required = True,
56
+                        type = datevalid)
57
+    parser.add_argument("-e", "--end-date", 
58
+                        dest = "enddate", 
59
+                        help = "end date for prediction; format: YYYY-MM-DD; default: 2018-02-01", 
60
+                        metavar="END_DATE", 
61
+                        required = True,
62
+                        type = datevalid)
63
+    parser.add_argument("-c", "--cluster",
64
+                        dest = "cluster",
65
+                        help = "cluster to predict for",
66
+                        type = int,
67
+                        required = True)
68
+    parser.add_argument("--csv",
69
+                        help="output as csv",
70
+                        action="store_true")
28 71
     args = parser.parse_args()
29 72
 
30
-    print(args)
73
+    if args.temp is None and args.weather_file is None:
74
+        parser.error("Either the temperature range or a weather "
75
+                     "dataset must be specified")
31 76
 
32 77
     mods = pickle.load(args.model_file)
33 78
 
34
-    pprint(mods)
79
+    if args.cluster not in mods["clusters"]:
80
+        parser.error(f"cluster ('{args.cluster}') not in model")
81
+
82
+    wdat = []
35 83
     
36
-    print(mods["max_temp"].predict())
84
+    if args.weather_file is not None:
85
+        weather = p.read_pickle(args.weather_file)
86
+        if (args.startdate < weather['temp_timestamp'].min() or 
87
+            args.enddate > weather['temp_timestamp'].max()):
88
+            parser.error("Start and or end date not in supplied weather dataset")
89
+
90
+        wantedtimes = p.date_range(args.startdate,
91
+                                   args.enddate, freq="30 min")
92
+        wantedtimes = p.Series(wantedtimes.round(freq="30 min"))
93
+        wanteddf = p.DataFrame(index=wantedtimes)
94
+        weather = wanteddf.join(weather.set_index(['temp_timestamp']),
95
+                                how='left').drop('temp_date', axis=1)
96
+        weather.index.name = "read_time"
97
+        weather = weather.fillna(method='ffill', axis=0)
98
+
99
+        # Add rolling columns
100
+        weather['min_rolling'] = weather['tmin_c'].rolling("1D").min()
101
+        weather['max_rolling'] = weather['tmax_c'].rolling("1D").max()
102
+
103
+        wharmstart = thirtyoffset(weather.index.min())
104
+        wharm = harmonic(weather.shape[0], period=365.25 * 48, start=wharmstart,
105
+                         harmonics=mods["weather_harmonics"])
106
+        wharm.index = wantedtimes
107
+        pred_max = weather['max_rolling'] - mods["max_temp"].predict(wharm)
108
+        pred_min = weather['min_rolling'] - mods["min_temp"].predict(wharm)
109
+        wdat = p.DataFrame({
110
+            "max_resid": pred_max,
111
+            "min_resid": pred_min
112
+        })
113
+
114
+    else:
115
+        mint = min(args.temp)
116
+        maxt = max(args.temp)
117
+        pred_max = maxt - predweather(mods["max_temp"],
118
+                               args.startdate,
119
+                               args.enddate,
120
+                               harmonics = mods["weather_harmonics"])
121
+        pred_min = mint - predweather(mods["min_temp"],
122
+                               args.startdate,
123
+                               args.enddate,
124
+                               harmonics = mods["weather_harmonics"])
125
+        wdat = p.DataFrame({
126
+            "max_resid": pred_max,
127
+            "min_resid": pred_min
128
+        })
129
+
130
+
131
+    dpred = p.DataFrame(
132
+        {
133
+            "predicted": preddemand(mods["icp"][args.cluster], wdat, mods["icp_harmonics"])
134
+        })
135
+
136
+    if args.csv:
137
+        signal(SIGPIPE, SIG_DFL) # Prevent broken pipe errors when piping to less or head
138
+        dpred.to_csv(args.output_file)
139
+    else:
140
+        dpred.to_pickle(args.output_file)
37 141
 
38
-    print(predweather(mods["max_temp"], "2019-01-01", "2019-02-01", harmonics = mods["weather_harmonics"]))
39 142
 
40 143
     args.model_file.close()
144
+    if args.weather_file is not None:
145
+        args.weather_file.close()
41 146
 
42 147
 
43 148
 if __name__ == "__main__":