Loading...

Smart Meters

This example uses the following datasets to predict peoples’ electricity consumption. You can download the Jupyter Notebook of the study here. We’ll use the following datasets:

sm_consumption

  • dateUTC: Date and time of the record.

  • meterID: Smart meter ID.

  • value: Electricity consumed during 30 minute interval (in kWh).

sm_weather

  • dateUTC: Date and time of the record.

  • temperature: Temperature.

  • humidity: Humidity.

sm_meters

  • longitude: Longitude.

  • latitude: Latitude.

  • residenceType: 1 for Single-Family; 2 for Multi-Family; 3 for Appartement.

We will follow the data science cycle (Data Exploration - Data Preparation - Data Modeling - Model Evaluation - Model Deployment) to solve this problem.

Initialization

This example uses the following version of VerticaPy:

import verticapy as vp

vp.__version__
Out[2]: '1.1.0'

Connect to Vertica. This example uses an existing connection called VerticaDSN. For details on how to create a connection, see the Connection tutorial. You can skip the below cell if you already have an established connection.

vp.connect("VerticaDSN")

Create the vDataFrame of the datasets:

sm_consumption = vp.read_csv(
    "sm_consumption.csv",
    dtype = {
        "meterID": "Integer",
        "dateUTC": "Timestamp(6)",
        "value": "Float(22)",
    }
)
sm_weather = vp.read_csv(
    "sm_weather.csv",
    dtype = {
        "dateUTC": "Timestamp(6)",
        "temperature": "Float(22)",
        "humidity": "Float(22)",
    }
)
sm_meters = vp.read_csv("sm_meters.csv")

Note

You can let Vertica automatically decide the data type, or you can manually force the data type on any column as seen above.

sm_consumption.head(100)
123
meterID
Int
100%
...
📅
dateUTC
Timestamp(6)
100%
123
value
Float
99%
10...2014-01-02 10:45:000.321
20...2014-01-02 11:15:000.305
30...2014-01-13 20:15:000.34
40...2014-01-18 00:30:000.828
50...2014-01-20 19:30:000.59
60...2014-01-21 12:30:000.327
70...2014-01-24 12:15:000.168
80...2014-01-27 22:45:000.495
90...2014-01-28 06:15:000.056
100...2014-01-28 19:00:001.566
110...2014-01-29 13:00:001.719
120...2014-02-04 03:45:000.045
130...2014-02-04 18:45:000.912
140...2014-02-05 06:45:000.018
150...2014-02-07 11:00:000.868
160...2014-02-07 22:15:001.262
170...2014-02-09 08:30:000.007
180...2014-02-11 19:00:000.094
190...2014-02-12 02:30:000.102
200...2014-02-13 02:45:000.097
210...2014-02-14 13:45:000.033
220...2014-02-15 02:00:000.181
230...2014-02-15 15:00:000.483
240...2014-02-16 00:00:000.195
250...2014-02-17 02:45:000.094
260...2014-02-19 07:00:000.095
270...2014-02-20 19:00:001.208
280...2014-02-23 14:45:000.75
290...2014-02-25 21:30:000.267
300...2014-03-07 15:15:000.415
310...2014-03-08 00:45:000.353
320...2014-03-12 22:30:000.511
330...2014-03-14 20:15:000.124
340...2014-03-16 06:45:000.42
350...2014-03-18 11:15:000.026
360...2014-03-20 19:00:000.239
370...2014-03-26 20:45:000.293
380...2014-04-01 01:00:000.167
390...2014-04-06 21:00:000.253
400...2014-04-11 16:45:000.22
410...2014-04-12 15:30:000.709
420...2014-04-13 09:15:000.192
430...2014-04-16 17:30:000.527
440...2014-04-21 09:45:000.133
450...2014-04-24 20:30:000.244
460...2014-04-26 03:00:000.047
470...2014-04-29 15:15:000.062
480...2014-05-05 07:30:000.182
490...2014-05-06 15:45:000.067
500...2014-05-06 18:45:000.192
510...2014-05-08 12:30:000.054
520...2014-05-14 00:15:000.577
530...2014-05-14 04:15:000.112
540...2014-05-16 16:00:000.064
550...2014-05-17 05:00:000.096
560...2014-05-18 09:30:000.065
570...2014-05-18 23:15:000.604
580...2014-05-19 08:30:000.134
590...2014-05-19 22:30:000.112
600...2014-05-28 01:00:000.284
610...2014-05-30 04:00:000.153
620...2014-06-02 18:15:000.558
630...2014-06-04 03:15:000.139
640...2014-06-06 02:30:000.085
650...2014-06-07 06:30:000.074
660...2014-06-11 08:00:000.092
670...2014-06-12 02:15:000.017
680...2014-06-14 14:00:000.016
690...2014-06-15 18:15:000.194
700...2014-06-16 18:30:000.78
710...2014-06-21 02:45:000.054
720...2014-06-24 05:30:000.048
730...2014-06-24 21:45:000.286
740...2014-06-25 08:00:000.618
750...2014-06-27 14:30:000.243
760...2014-07-02 22:30:000.617
770...2014-07-02 23:15:000.14
780...2014-07-03 13:15:000.976
790...2014-07-04 11:30:000.133
800...2014-07-06 07:00:000.037
810...2014-07-08 10:00:000.014
820...2014-07-10 12:45:000.163
830...2014-07-11 03:45:000.044
840...2014-07-15 04:30:000.068
850...2014-07-16 10:15:000.026
860...2014-07-20 11:45:001.227
870...2014-07-25 11:00:000.038
880...2014-07-25 11:45:000.05
890...2014-07-26 04:15:000.096
900...2014-07-27 10:00:000.157
910...2014-07-29 17:30:000.729
920...2014-07-30 04:15:000.437
930...2014-07-31 02:15:000.068
940...2014-07-31 12:30:002.76
950...2014-08-03 05:00:000.088
960...2014-08-03 23:30:000.748
970...2014-08-04 15:30:000.074
980...2014-08-05 13:15:000.339
990...2014-08-09 06:00:000.026
1000...2014-08-13 08:30:000.043
sm_weather.head(100)
📅
dateUTC
Timestamp(6)
100%
...
123
temperature
Float
100%
123
humidity
Float
100%
12014-01-01 01:30:00...37.4100.0
22014-01-01 02:00:00...39.293.0
32014-01-01 05:30:00...39.287.0
42014-01-01 08:30:00...37.487.0
52014-01-01 10:00:00...37.493.0
62014-01-01 11:30:00...37.493.0
72014-01-01 13:00:00...39.287.0
82014-01-01 15:30:00...39.287.0
92014-01-01 17:00:00...39.287.0
102014-01-01 19:30:00...37.493.0
112014-01-01 20:00:00...39.287.0
122014-01-01 22:30:00...39.287.0
132014-01-01 23:00:00...39.287.0
142014-01-01 23:30:00...39.281.0
152014-01-02 00:00:00...38.076.0
162014-01-02 02:30:00...37.481.0
172014-01-02 03:00:00...37.481.0
182014-01-02 04:00:00...37.481.0
192014-01-02 05:00:00...35.693.0
202014-01-02 05:30:00...37.481.0
212014-01-02 07:30:00...37.481.0
222014-01-02 09:00:00...37.475.0
232014-01-02 09:30:00...37.481.0
242014-01-02 12:30:00...41.070.0
252014-01-02 13:30:00...41.076.0
262014-01-02 14:00:00...41.076.0
272014-01-02 15:00:00...41.076.0
282014-01-02 18:00:00...39.070.0
292014-01-02 18:30:00...37.481.0
302014-01-02 20:00:00...37.481.0
312014-01-02 21:00:00...39.265.0
322014-01-02 23:30:00...39.265.0
332014-01-03 00:00:00...39.048.0
342014-01-03 04:00:00...37.470.0
352014-01-03 05:00:00...37.470.0
362014-01-03 06:00:00...38.050.0
372014-01-03 10:30:00...39.261.0
382014-01-03 11:30:00...39.261.0
392014-01-03 12:00:00...39.048.0
402014-01-03 17:00:00...35.670.0
412014-01-03 22:00:00...33.881.0
422014-01-04 01:30:00...33.881.0
432014-01-04 04:30:00...35.675.0
442014-01-04 12:30:00...35.6100.0
452014-01-04 16:00:00...33.893.0
462014-01-04 16:30:00...33.893.0
472014-01-04 17:30:00...32.0100.0
482014-01-04 18:30:00...32.0100.0
492014-01-04 22:30:00...28.4100.0
502014-01-05 00:00:00...38.083.0
512014-01-05 07:30:00...33.8100.0
522014-01-05 10:30:00...39.281.0
532014-01-05 11:00:00...39.281.0
542014-01-05 12:00:00...41.062.0
552014-01-05 16:30:00...33.887.0
562014-01-05 17:00:00...33.887.0
572014-01-05 19:30:00...32.080.0
582014-01-05 21:00:00...30.280.0
592014-01-05 22:00:00...30.286.0
602014-01-05 22:30:00...32.080.0
612014-01-05 23:30:00...33.875.0
622014-01-06 00:30:00...33.875.0
632014-01-06 02:00:00...32.075.0
642014-01-06 02:30:00...32.080.0
652014-01-06 03:00:00...32.080.0
662014-01-06 04:00:00...33.870.0
672014-01-06 04:30:00...33.865.0
682014-01-06 08:30:00...28.486.0
692014-01-06 11:30:00...32.075.0
702014-01-06 15:00:00...35.660.0
712014-01-06 16:00:00...32.069.0
722014-01-06 16:30:00...30.275.0
732014-01-06 19:30:00...28.486.0
742014-01-06 22:00:00...28.480.0
752014-01-06 22:30:00...26.686.0
762014-01-07 01:00:00...28.480.0
772014-01-07 02:30:00...28.480.0
782014-01-07 08:00:00...28.486.0
792014-01-07 09:30:00...30.280.0
802014-01-07 11:30:00...33.875.0
812014-01-07 13:00:00...35.675.0
822014-01-07 13:30:00...37.465.0
832014-01-07 14:00:00...37.465.0
842014-01-07 15:00:00...37.465.0
852014-01-07 15:30:00...35.675.0
862014-01-07 17:30:00...32.080.0
872014-01-07 18:00:00...30.085.0
882014-01-07 18:30:00...32.080.0
892014-01-07 20:30:00...30.286.0
902014-01-07 21:00:00...32.080.0
912014-01-07 21:30:00...28.493.0
922014-01-07 22:30:00...30.286.0
932014-01-08 03:30:00...35.681.0
942014-01-08 05:00:00...35.693.0
952014-01-08 06:00:00...33.090.0
962014-01-08 06:30:00...32.093.0
972014-01-08 08:30:00...32.093.0
982014-01-08 09:00:00...33.887.0
992014-01-08 10:30:00...37.475.0
1002014-01-08 12:30:00...41.070.0
sm_meters.head(100)
📅
dateUTC
Timestamp(6)
100%
...
123
temperature
Float
100%
123
humidity
Float
100%
12014-01-01 03:00:00...39.293.0
22014-01-01 04:00:00...39.293.0
32014-01-01 04:30:00...39.293.0
42014-01-01 09:00:00...37.487.0
52014-01-01 11:00:00...37.487.0
62014-01-01 12:00:00...38.085.0
72014-01-01 13:30:00...39.287.0
82014-01-01 17:30:00...37.487.0
92014-01-01 18:30:00...37.487.0
102014-01-01 21:00:00...39.287.0
112014-01-02 01:30:00...37.481.0
122014-01-02 04:30:00...35.687.0
132014-01-02 10:00:00...39.275.0
142014-01-02 11:30:00...41.070.0
152014-01-02 14:30:00...41.076.0
162014-01-02 21:30:00...39.265.0
172014-01-02 22:00:00...39.265.0
182014-01-02 23:00:00...39.261.0
192014-01-03 00:30:00...39.261.0
202014-01-03 01:00:00...39.265.0
212014-01-03 02:00:00...37.470.0
222014-01-03 03:00:00...37.470.0
232014-01-03 08:30:00...37.465.0
242014-01-03 10:00:00...37.465.0
252014-01-03 11:00:00...39.256.0
262014-01-03 12:30:00...39.261.0
272014-01-03 13:00:00...39.261.0
282014-01-03 13:30:00...39.261.0
292014-01-03 15:00:00...37.465.0
302014-01-03 17:30:00...33.870.0
312014-01-03 19:30:00...35.670.0
322014-01-03 20:00:00...35.670.0
332014-01-03 20:30:00...35.670.0
342014-01-03 23:30:00...33.887.0
352014-01-04 01:00:00...33.881.0
362014-01-04 02:00:00...35.670.0
372014-01-04 03:00:00...35.675.0
382014-01-04 05:00:00...35.675.0
392014-01-04 05:30:00...35.675.0
402014-01-04 06:00:00...38.083.0
412014-01-04 06:30:00...35.681.0
422014-01-04 07:30:00...35.681.0
432014-01-04 08:30:00...35.681.0
442014-01-04 11:30:00...35.6100.0
452014-01-04 12:00:00...36.098.0
462014-01-04 14:00:00...35.6100.0
472014-01-04 17:00:00...33.8100.0
482014-01-04 18:00:00...31.0100.0
492014-01-04 19:00:00...32.0100.0
502014-01-04 20:00:00...30.2100.0
512014-01-04 21:00:00...28.4100.0
522014-01-04 22:00:00...29.3100.0
532014-01-04 23:30:00...28.4100.0
542014-01-05 01:00:00...26.6100.0
552014-01-05 02:00:00...24.8100.0
562014-01-05 04:00:00...28.4100.0
572014-01-05 05:30:00...30.2100.0
582014-01-05 07:00:00...33.8100.0
592014-01-05 08:00:00...37.4100.0
602014-01-05 13:30:00...41.070.0
612014-01-05 16:00:00...37.481.0
622014-01-05 17:30:00...33.887.0
632014-01-05 18:30:00...32.080.0
642014-01-05 21:30:00...30.280.0
652014-01-06 01:30:00...32.080.0
662014-01-06 05:30:00...32.069.0
672014-01-06 06:30:00...32.069.0
682014-01-06 07:30:00...26.686.0
692014-01-06 08:00:00...26.686.0
702014-01-06 09:30:00...28.486.0
712014-01-06 10:30:00...32.075.0
722014-01-06 13:00:00...33.870.0
732014-01-06 14:00:00...35.660.0
742014-01-06 18:00:00...28.077.0
752014-01-06 20:30:00...28.486.0
762014-01-06 21:00:00...28.486.0
772014-01-06 23:00:00...28.480.0
782014-01-07 00:00:00...28.074.0
792014-01-07 00:30:00...28.480.0
802014-01-07 04:00:00...28.486.0
812014-01-07 07:30:00...28.486.0
822014-01-07 09:00:00...28.486.0
832014-01-07 10:30:00...32.080.0
842014-01-07 11:00:00...32.080.0
852014-01-07 12:00:00...34.066.0
862014-01-08 00:00:00...29.084.0
872014-01-08 00:30:00...30.286.0
882014-01-08 01:00:00...32.080.0
892014-01-08 02:00:00...32.093.0
902014-01-08 04:00:00...33.887.0
912014-01-08 04:30:00...35.687.0
922014-01-08 05:30:00...33.893.0
932014-01-08 09:30:00...35.681.0
942014-01-08 12:00:00...40.061.0
952014-01-08 13:00:00...41.067.5
962014-01-08 14:30:00...41.065.0
972014-01-08 23:30:00...33.887.0
982014-01-09 03:00:00...26.6100.0
992014-01-09 05:00:00...33.893.0
1002014-01-09 07:00:00...35.693.0

Data Exploration and Preparation

Predicting energy consumption in households is very important. Surges in electricity use could cause serious power outages. In our case, we’ll be using data on general household energy consumption in Ireland to predict consumption at various times.

In order to join the different data sources, we need to assume that the weather will be approximately the same across the entirety of Ireland. We’ll use the date and time as the key to join sm_weather and sm_consumption.

Joining different datasets with interpolation

In VerticaPy, you can interpolate joins; Vertica will find the closest timestamp to the key and join the result.

sm_consumption_weather = sm_consumption.join(
    sm_weather,
    how = "left",
    on_interpolate = {"dateUTC": "dateUTC"},
    expr1 = ["dateUTC", "meterID", "value"],
    expr2 = ["humidity", "temperature"],
)
sm_consumption_weather.head(100)
📅
dateUTC
Timestamp(29)
100%
...
123
humidity
Float(22)
100%
123
temperature
Float(22)
100%
12014-01-01 00:00:00...95.038.0
22014-01-01 00:00:00...95.038.0
32014-01-01 00:00:00...95.038.0
42014-01-01 00:00:00...95.038.0
52014-01-01 00:00:00...95.038.0
62014-01-01 00:00:00...95.038.0
72014-01-01 00:00:00...95.038.0
82014-01-01 00:00:00...95.038.0
92014-01-01 00:00:00...95.038.0
102014-01-01 00:00:00...95.038.0
112014-01-01 00:00:00...95.038.0
122014-01-01 00:00:00...95.038.0
132014-01-01 00:00:00...95.038.0
142014-01-01 00:00:00...95.038.0
152014-01-01 00:00:00...95.038.0
162014-01-01 00:00:00...95.038.0
172014-01-01 00:00:00...95.038.0
182014-01-01 00:00:00...95.038.0
192014-01-01 00:00:00...95.038.0
202014-01-01 00:00:00...95.038.0
212014-01-01 00:15:00...95.038.0
222014-01-01 00:15:00...95.038.0
232014-01-01 00:15:00...95.038.0
242014-01-01 00:15:00...95.038.0
252014-01-01 00:15:00...95.038.0
262014-01-01 00:15:00...95.038.0
272014-01-01 00:15:00...95.038.0
282014-01-01 00:15:00...95.038.0
292014-01-01 00:15:00...95.038.0
302014-01-01 00:15:00...95.038.0
312014-01-01 00:15:00...95.038.0
322014-01-01 00:15:00...95.038.0
332014-01-01 00:30:00...93.037.4
342014-01-01 00:30:00...93.037.4
352014-01-01 00:30:00...93.037.4
362014-01-01 00:30:00...93.037.4
372014-01-01 00:30:00...93.037.4
382014-01-01 00:30:00...93.037.4
392014-01-01 00:30:00...93.037.4
402014-01-01 00:30:00...93.037.4
412014-01-01 00:30:00...93.037.4
422014-01-01 00:30:00...93.037.4
432014-01-01 00:30:00...93.037.4
442014-01-01 00:30:00...93.037.4
452014-01-01 00:30:00...93.037.4
462014-01-01 00:30:00...93.037.4
472014-01-01 00:30:00...93.037.4
482014-01-01 00:30:00...93.037.4
492014-01-01 00:30:00...93.037.4
502014-01-01 00:30:00...93.037.4
512014-01-01 00:30:00...93.037.4
522014-01-01 00:30:00...93.037.4
532014-01-01 00:45:00...93.037.4
542014-01-01 00:45:00...93.037.4
552014-01-01 00:45:00...93.037.4
562014-01-01 00:45:00...93.037.4
572014-01-01 00:45:00...93.037.4
582014-01-01 00:45:00...93.037.4
592014-01-01 00:45:00...93.037.4
602014-01-01 00:45:00...93.037.4
612014-01-01 00:45:00...93.037.4
622014-01-01 00:45:00...93.037.4
632014-01-01 00:45:00...93.037.4
642014-01-01 01:00:00...100.037.4
652014-01-01 01:00:00...100.037.4
662014-01-01 01:00:00...100.037.4
672014-01-01 01:00:00...100.037.4
682014-01-01 01:00:00...100.037.4
692014-01-01 01:00:00...100.037.4
702014-01-01 01:00:00...100.037.4
712014-01-01 01:00:00...100.037.4
722014-01-01 01:00:00...100.037.4
732014-01-01 01:00:00...100.037.4
742014-01-01 01:00:00...100.037.4
752014-01-01 01:00:00...100.037.4
762014-01-01 01:00:00...100.037.4
772014-01-01 01:00:00...100.037.4
782014-01-01 01:00:00...100.037.4
792014-01-01 01:00:00...100.037.4
802014-01-01 01:00:00...100.037.4
812014-01-01 01:00:00...100.037.4
822014-01-01 01:15:00...100.037.4
832014-01-01 01:15:00...100.037.4
842014-01-01 01:15:00...100.037.4
852014-01-01 01:15:00...100.037.4
862014-01-01 01:15:00...100.037.4
872014-01-01 01:15:00...100.037.4
882014-01-01 01:15:00...100.037.4
892014-01-01 01:15:00...100.037.4
902014-01-01 01:15:00...100.037.4
912014-01-01 01:15:00...100.037.4
922014-01-01 01:15:00...100.037.4
932014-01-01 01:15:00...100.037.4
942014-01-01 01:15:00...100.037.4
952014-01-01 01:15:00...100.037.4
962014-01-01 01:15:00...100.037.4
972014-01-01 01:15:00...100.037.4
982014-01-01 01:15:00...100.037.4
992014-01-01 01:15:00...100.037.4
1002014-01-01 01:15:00...100.037.4

Segmenting Latitude & Longitude using Clustering

The dataset sm_meters is pretty important. In particular, the type of residence is probably a good predictor for electricity usage. We can create clusters of the different regions with KMeans clustering based on longitude and latitude. Let’s find the most suitable k using an elbow curve and scatter plot.

sm_meters.agg(["min", "max"])
...
min
max
"meterID"...0.0999.0
"residenceType"...1.03.0
"latitude"...51.796460077021254.0270361317983
"longitude"...-9.16352332036362-6.07134572494937
from verticapy.machine_learning.model_selection import elbow

from verticapy.datasets import load_world

# Geo Plots are only available in Matplotlib.
vp.set_option("plotting_lib", "matplotlib")

# Loading the world map.
world = load_world()

# Plotting the final map.
df = world.to_geopandas(geometry = "geometry")

df = df[df["country"].isin(["Ireland", "United Kingdom"])]

ax = df.plot(
    edgecolor = "black",
    color = "white",
    figsize = (10, 9),
)


sm_meters.scatter(["longitude", "latitude"], ax = ax)
Out[10]: <Axes: xlabel='longitude', ylabel='latitude'>
_images/examples_sm_meters_scatter.png _images/examples_sm_meters_scatter1.png

Based on the scatter plot, five seems like the optimal number of clusters. Let’s verify this hypothesis using an elbow() curve.

# Switching back to Plotly.
vp.set_option("plotting_lib", "plotly")

elbow(sm_meters, ["longitude", "latitude"], n_cluster = (3, 8))

The elbow curve seems to confirm that five is the optimal number of clusters, so let’s create a KMeans model with that in mind.

from verticapy.machine_learning.vertica import KMeans

model = KMeans(
    n_cluster = 5,
    init = [
        (-6.26980, 53.38127),
        (-9.06178, 53.25998),
        (-8.48641, 51.90216),
        (-7.12408, 52.24610),
        (-8.63985, 52.65945),
    ],
)


model.fit(
    sm_meters,
    [
        "longitude",
         "latitude",
    ],
)



=======
centers
=======
longitude|latitude
---------+--------
-9.06178 |53.25998
-8.63985 |52.65945
-8.48641 |51.90216
-7.12408 |52.24610
-6.26980 |53.38127


=======
metrics
=======
Evaluation metrics:
     Total Sum of Squares: 1209.2077
     Within-Cluster Sum of Squares: 
         Cluster 0: 0.099754154
         Cluster 1: 0.2779225
         Cluster 2: 0.53464463
         Cluster 3: 0.2657853
         Cluster 4: 17.892423
     Total Within-Cluster Sum of Squares: 19.07053
     Between-Cluster Sum of Squares: 1190.1372
     Between-Cluster SS / Total SS: 98.42%
 Number of iterations performed: 1
 Converged: True
 Call:
kmeans('"public"."_verticapy_tmp_kmeans_v_mldb_6b20cd6e97b411efa8720242ac120002_"', '"public"."_verticapy_tmp_view_v_mldb_6b9d465097b411efa8720242ac120002_"', '"longitude", "latitude"', 5
USING PARAMETERS max_iterations=300, epsilon=0.0001, initial_centers_table='"public"."_verticapy_tmp_kmeans_init_v_mldb_6bc3b5d897b411efa8720242ac120002_"', distance_method='euclidean')

Let’s add our clusters to the vDataFrame.

sm_meters = model.predict(sm_meters, name = "region")

Let’s draw a scatter plot of the different regions.

# Geo Plots are only available in Matplotlib.
vp.set_option("plotting_lib", "matplotlib")

ax = df.plot(
    edgecolor = "black",
    color = "white",
    figsize = (10, 9),
)


sm_meters.scatter(
    ["longitude", "latitude"],
    by = "region",
    max_cardinality = 10,
    ax = ax,
)

Out[17]: <Axes: xlabel='longitude', ylabel='latitude'>
_images/examples_sm_meters_scatter_2.png _images/examples_sm_meters_scatter_21.png

Dataset Enrichment

Let’s join sm_meters with sm_consumption_weather.

sm_consumption_weather_region = sm_consumption_weather.join(
    sm_meters,
    how = "natural",
    expr1 = ["*"],
    expr2 = [
        "residenceType",
        "region",
    ],
)
sm_consumption_weather_region.head(100)
📅
dateUTC
Timestamp(29)
100%
...
123
residenceType
Integer
100%
123
region
Integer
100%
12014-01-01 12:30:00...12
22014-01-01 12:30:00...34
32014-01-01 12:30:00...14
42014-01-01 12:30:00...34
52014-01-01 12:45:00...22
62014-01-01 12:45:00...34
72014-01-01 12:45:00...14
82014-01-01 12:45:00...14
92014-01-01 12:45:00...34
102014-01-01 12:45:00...30
112014-01-01 13:00:00...14
122014-01-01 13:00:00...34
132014-01-01 13:00:00...24
142014-01-01 13:00:00...32
152014-01-01 13:15:00...14
162014-01-01 13:15:00...14
172014-01-01 13:15:00...32
182014-01-01 13:15:00...10
192014-01-01 13:30:00...34
202014-01-01 13:30:00...14
212014-01-01 13:30:00...13
222014-01-01 13:30:00...14
232014-01-01 13:30:00...14
242014-01-01 13:45:00...34
252014-01-01 13:45:00...34
262014-01-01 13:45:00...32
272014-01-01 13:45:00...14
282014-01-01 14:00:00...13
292014-01-01 14:00:00...12
302014-01-01 14:00:00...14
312014-01-01 14:15:00...11
322014-01-01 14:15:00...14
332014-01-01 14:15:00...14
342014-01-01 14:15:00...12
352014-01-01 14:15:00...14
362014-01-01 14:15:00...22
372014-01-01 14:15:00...14
382014-01-01 14:30:00...14
392014-01-01 14:30:00...14
402014-01-01 14:30:00...14
412014-01-01 14:30:00...34
422014-01-01 14:45:00...14
432014-01-01 14:45:00...24
442014-01-01 14:45:00...14
452014-01-01 14:45:00...30
462014-01-01 14:45:00...14
472014-01-01 14:45:00...14
482014-01-01 15:00:00...14
492014-01-01 15:00:00...34
502014-01-01 15:00:00...13
512014-01-01 15:00:00...14
522014-01-01 15:00:00...14
532014-01-01 15:15:00...12
542014-01-01 15:15:00...34
552014-01-01 15:15:00...14
562014-01-01 15:15:00...14
572014-01-01 15:15:00...34
582014-01-01 15:15:00...12
592014-01-01 15:30:00...34
602014-01-01 15:30:00...14
612014-01-01 15:30:00...24
622014-01-01 15:30:00...13
632014-01-01 15:45:00...34
642014-01-01 15:45:00...14
652014-01-01 15:45:00...11
662014-01-01 15:45:00...12
672014-01-01 15:45:00...34
682014-01-01 16:00:00...31
692014-01-01 16:00:00...32
702014-01-01 16:00:00...13
712014-01-01 16:00:00...34
722014-01-01 16:00:00...14
732014-01-01 16:15:00...31
742014-01-01 16:15:00...34
752014-01-01 16:30:00...34
762014-01-01 16:30:00...14
772014-01-01 16:30:00...32
782014-01-01 16:30:00...14
792014-01-01 16:30:00...14
802014-01-01 16:30:00...22
812014-01-01 16:30:00...12
822014-01-01 16:45:00...14
832014-01-01 16:45:00...34
842014-01-01 17:00:00...14
852014-01-01 17:00:00...14
862014-01-01 17:00:00...14
872014-01-01 17:15:00...14
882014-01-01 17:15:00...32
892014-01-01 17:15:00...12
902014-01-01 17:15:00...22
912014-01-01 17:15:00...14
922014-01-01 17:30:00...24
932014-01-01 17:30:00...14
942014-01-01 17:30:00...14
952014-01-01 17:30:00...24
962014-01-01 17:30:00...14
972014-01-01 17:30:00...34
982014-01-01 17:30:00...12
992014-01-01 17:30:00...13
1002014-01-01 17:30:00...24

Handling Missing Values

Let’s take care of our missing values.

sm_consumption_weather_region.count_percent()
...
count
percent
"dateUTC"...1188432.0100.0
"meterID"...1188432.0100.0
"humidity"...1188432.0100.0
"temperature"...1188432.0100.0
"residenceType"...1188432.0100.0
"region"...1188432.0100.0
"value"...1188412.099.998

The variable value has a few missing values that we can drop.

sm_consumption_weather_region["value"].dropna()
sm_consumption_weather_region.count()
count
"dateUTC"1188412.0
"meterID"1188412.0
"value"1188412.0
"humidity"1188412.0
"temperature"1188412.0
"residenceType"1188412.0
"region"1188412.0

Interpolation & Aggregations

Since power outages seem relatively common in each area, and the value represents the electricity consumed during 30 minute intervals (in kWh), it’d be a good idea to interpolate and aggregate the data to get a monthly average in electricity consumption per region.

Let’s save our new dataset in the Vertica database.

vp.drop("sm_consumption_weather_region", method = "table")
Out[18]: True

sm_consumption_weather_region.to_db(
    "sm_consumption_weather_region",
    relation_type = "table",
)

Out[19]: 
None              dateUTC    ...    residenceType    region  
1     2014-12-30 17:00:00    ...                1         4  
2     2014-09-15 10:30:00    ...                1         4  
3     2014-09-30 18:15:00    ...                1         4  
4     2015-04-14 15:15:00    ...                1         4  
5     2015-07-05 10:30:00    ...                1         4  
6     2014-06-22 20:45:00    ...                1         4  
7     2015-09-08 16:30:00    ...                1         4  
8     2014-11-28 05:15:00    ...                1         4  
9     2014-08-11 22:00:00    ...                1         4  
10    2015-05-03 20:45:00    ...                1         4  
11    2014-08-27 16:15:00    ...                1         4  
12    2015-04-17 01:00:00    ...                1         4  
13    2014-07-05 22:45:00    ...                1         4  
14    2015-05-04 23:15:00    ...                1         4  
15    2015-04-17 09:15:00    ...                1         4  
16    2014-12-01 15:15:00    ...                1         4  
17    2014-11-13 20:00:00    ...                1         4  
18    2014-06-11 12:00:00    ...                1         4  
19    2014-04-03 15:45:00    ...                1         4  
20    2015-08-22 08:45:00    ...                1         4  
...                   ...    ...              ...       ...  
Rows: 1-20 of 1188412 | Columns: 4

sm_consumption_weather_region_clean = vp.vDataFrame("sm_consumption_weather_region")

To get an equally-sliced dataset, we can then interpolate to fill any gaps. This operation is essential for creating correct time series models.

sm_consumption_weather_region_clean = sm_consumption_weather_region_clean.interpolate(
    ts = "dateUTC",
    rule = "30 minutes",
    method = {
        "value": "linear",
        "humidity": "linear",
        "temperature": "linear",
        "residenceType": "ffill",
        "region": "ffill",
    },
    by = ["meterID"],
)
sm_consumption_weather_region_clean.head(100)
📅
dateUTC
Timestamp(29)
100%
...
123
residenceType
Integer
99%
123
region
Integer
99%
12014-01-01 05:30:00...[null][null]
22014-01-01 06:00:00...34
32014-01-01 06:30:00...34
42014-01-01 07:00:00...34
52014-01-01 07:30:00...34
62014-01-01 08:00:00...34
72014-01-01 08:30:00...34
82014-01-01 09:00:00...34
92014-01-01 09:30:00...34
102014-01-01 10:00:00...34
112014-01-01 10:30:00...34
122014-01-01 11:00:00...34
132014-01-01 11:30:00...34
142014-01-01 12:00:00...34
152014-01-01 12:30:00...34
162014-01-01 13:00:00...34
172014-01-01 13:30:00...34
182014-01-01 14:00:00...34
192014-01-01 14:30:00...34
202014-01-01 15:00:00...34
212014-01-01 15:30:00...34
222014-01-01 16:00:00...34
232014-01-01 16:30:00...34
242014-01-01 17:00:00...34
252014-01-01 17:30:00...34
262014-01-01 18:00:00...34
272014-01-01 18:30:00...34
282014-01-01 19:00:00...34
292014-01-01 19:30:00...34
302014-01-01 20:00:00...34
312014-01-01 20:30:00...34
322014-01-01 21:00:00...34
332014-01-01 21:30:00...34
342014-01-01 22:00:00...34
352014-01-01 22:30:00...34
362014-01-01 23:00:00...34
372014-01-01 23:30:00...34
382014-01-02 00:00:00...34
392014-01-02 00:30:00...34
402014-01-02 01:00:00...34
412014-01-02 01:30:00...34
422014-01-02 02:00:00...34
432014-01-02 02:30:00...34
442014-01-02 03:00:00...34
452014-01-02 03:30:00...34
462014-01-02 04:00:00...34
472014-01-02 04:30:00...34
482014-01-02 05:00:00...34
492014-01-02 05:30:00...34
502014-01-02 06:00:00...34
512014-01-02 06:30:00...34
522014-01-02 07:00:00...34
532014-01-02 07:30:00...34
542014-01-02 08:00:00...34
552014-01-02 08:30:00...34
562014-01-02 09:00:00...34
572014-01-02 09:30:00...34
582014-01-02 10:00:00...34
592014-01-02 10:30:00...34
602014-01-02 11:00:00...34
612014-01-02 11:30:00...34
622014-01-02 12:00:00...34
632014-01-02 12:30:00...34
642014-01-02 13:00:00...34
652014-01-02 13:30:00...34
662014-01-02 14:00:00...34
672014-01-02 14:30:00...34
682014-01-02 15:00:00...34
692014-01-02 15:30:00...34
702014-01-02 16:00:00...34
712014-01-02 16:30:00...34
722014-01-02 17:00:00...34
732014-01-02 17:30:00...34
742014-01-02 18:00:00...34
752014-01-02 18:30:00...34
762014-01-02 19:00:00...34
772014-01-02 19:30:00...34
782014-01-02 20:00:00...34
792014-01-02 20:30:00...34
802014-01-02 21:00:00...34
812014-01-02 21:30:00...34
822014-01-02 22:00:00...34
832014-01-02 22:30:00...34
842014-01-02 23:00:00...34
852014-01-02 23:30:00...34
862014-01-03 00:00:00...34
872014-01-03 00:30:00...34
882014-01-03 01:00:00...34
892014-01-03 01:30:00...34
902014-01-03 02:00:00...34
912014-01-03 02:30:00...34
922014-01-03 03:00:00...34
932014-01-03 03:30:00...34
942014-01-03 04:00:00...34
952014-01-03 04:30:00...34
962014-01-03 05:00:00...34
972014-01-03 05:30:00...34
982014-01-03 06:00:00...34
992014-01-03 06:30:00...34
1002014-01-03 07:00:00...34

Let’s aggregate the data to figure out the monthly energy consumption for each smart meter. We can then save the result in the Vertica database.

import verticapy.sql.functions as fun

sm_consumption_weather_region_clean["month"] = "MONTH(dateUTC)"
sm_consumption_weather_region_clean["date_month"] = "DATE_TRUNC('MONTH', dateUTC::date)"
sm_consumption_month = sm_consumption_weather_region_clean.groupby(
    columns = [
        "meterID",
        "region",
        "residenceType",
        "month",
        "date_month",
    ],
    expr = [
        fun.sum(sm_consumption_weather_region["value"])._as("value"),
        fun.avg(sm_consumption_weather_region["temperature"])._as("avg_temperature"),
        fun.avg(sm_consumption_weather_region["humidity"])._as("avg_humidity"),
    ],
).filter(
    "date_month < '2015-09-01'",
)
vp.drop("sm_consumption_month", method = "table")
sm_consumption_month.to_db(
    "sm_consumption_month",
    relation_type = "table",
    inplace = True,
)
123
meterID
Int
100%
...
123
region
Int
97%
123
avg_humidity
Float
97%
12...[null][null]
22...484.9491344603949
32...494.0992998737685
42...486.0871432645725
52...490.4227418530055
62...480.8285802271696
72...482.2095048876506
82...485.081830737512
92...477.0781891119151
102...484.3597425444918
112...478.7060994156184
122...482.169875343245
132...480.3458444814076
142...483.3348880025485
152...479.4181890210453
162...484.0634813017688
172...481.8807510916972
182...484.3442042309829
192...486.9737490248736
202...487.2311202524699

Understanding the Data & Detecting Outliers

Looking at three different smart meters, we can see a clear decrease in energy consumption during the summer followed by a sharp increase in the winter.

# Switching back to Plotly.
vp.set_option("plotting_lib", "plotly")

sm_consumption_month[sm_consumption_month["meterID"] == 10]["value"].plot(ts = "date_month")
sm_consumption_month[sm_consumption_month["meterID"] == 12]["value"].plot(ts = "date_month")
sm_consumption_month[sm_consumption_month["meterID"] == 14]["value"].plot(ts = "date_month")

This behavior seems to be seasonal, but we don’t have enough data to prove this.

Let’s find outliers in the distribution by computing the ZSCORE` per meterID.

std = fun.std(sm_consumption_month["value"])._over(by = [sm_consumption_month["meterID"]])
avg = fun.avg(sm_consumption_month["value"])._over(by = [sm_consumption_month["meterID"]])
sm_consumption_month["value_zscore"] = (sm_consumption_month["value"] - avg) / std
sm_consumption_month.search("value_zscore > 4")
123
meterID
Integer
100%
...
123
avg_humidity
Float(22)
100%
123
value_zscore
Float(22)
100%
1399...88.77303609147824.07298404322647
2364...89.96525230282624.00855200430863
3809...86.47158029841174.0151606376986
4951...73.63134617681084.01829822269677

Four smart meters are outliers in energy consumption. We’ll need to investigate to get more information.

sm_consumption_month[sm_consumption_month["meterID"] == 364]["value"].plot(ts = "date_month")
sm_consumption_month[sm_consumption_month["meterID"] == 399]["value"].plot(ts = "date_month")
sm_consumption_month[sm_consumption_month["meterID"] == 809]["value"].plot(ts = "date_month")
sm_consumption_month[sm_consumption_month["meterID"] == 951]["value"].plot(ts = "date_month")

Data Encoding & Bivariate Analysis

Since most of our data is categorical, let’s encode them with One-hot encoding. We can then examine the correlations between the various categories.

sm_consumption_month = sm_consumption_month.one_hot_encode(
    ["region", "residenceType", "month"],
    drop_first = False,
    max_cardinality = 20,
)
sm_consumption_month.head(100)
123
meterID
Int
100%
...
123
month_11
Bool
100%
123
month_12
Bool
100%
12...00
22...00
32...00
42...00
52...00
62...00
72...00
82...00
92...00
102...00
112...00
122...00
132...00
142...00
152...00
162...00
172...00
182...00
192...00
202...10
212...01
223...00
233...00
243...00
253...00
263...00
273...00
283...00
293...00
303...00
313...00
323...00
333...00
343...00
353...00
363...00
373...00
383...00
393...00
403...10
413...01
4216...00
4316...00
4416...00
4516...00
4616...00
4716...00
4816...00
4916...00
5016...00
5116...00
5216...00
5316...00
5416...00
5516...00
5616...00
5716...00
5816...00
5916...00
6016...00
6116...10
6216...01
6325...00
6425...00
6525...00
6625...00
6725...00
6825...00
6925...00
7025...00
7125...00
7225...00
7325...00
7425...00
7525...00
7625...00
7725...00
7825...00
7925...00
8025...00
8125...10
8225...01
8330...00
8430...00
8530...00
8630...00
8730...00
8830...00
8930...00
9030...00
9130...00
9230...00
9330...00
9430...00
9530...00
9630...00
9730...00
9830...00
9930...00
10030...00

Let’s compute the Pearson correlation matrix.

sm_consumption_month.corr()

There’s a clear correlation between the month and energy consumption, but this isn’t causal. Instead, we can think of the weather as having the direct influence on energy consumption. To accomodate for this view, we’ll use the temperature as a predictor (rather than the month).

sm_consumption_month.corr(focus = "value")

Global Behavior

Let’s look at this globally.

sm_consumption_final = sm_consumption_month.groupby(
    ["date_month"],
    [
        fun.avg(sm_consumption_month["avg_temperature"])._as("avg_temperature"),
        fun.avg(sm_consumption_month["avg_humidity"])._as("avg_humidity"),
        fun.avg(sm_consumption_month["value"])._as("avg_value"),
    ],
)
sm_consumption_final.plot(ts = "date_month", columns = ["avg_value"])

We expect to see a fall in energy consumption during summer and then an increase during the winter. A simple prediction could use the average value a year before.

sm_consumption_final["prediction"] = fun.case_when(
    sm_consumption_final["date_month"] < '2015-01-01', sm_consumption_final["avg_value"],
    fun.lag(sm_consumption_final["avg_value"], 12)._over(order_by = ["date_month"]),
)
sm_consumption_final.plot(ts = "date_month", columns = ["prediction", "avg_value"])
sm_consumption_final.score("avg_value", "prediction", "r2")
Out[21]: 0.987990336935642

As expected, our model’s score is excellent.

Let’s use machine learning to understand the influence of the weather and the humidity on energy consumption.

Machine Learning

Let’s create our model.

from verticapy.machine_learning.vertica import LinearRegression

predictors = [
    "avg_temperature",
    "avg_humidity",
]


model = LinearRegression(solver = "BFGS")

model.fit(
    sm_consumption_final,
    predictors,
    "avg_value",
)



=======
details
=======
   predictor   |coefficient| std_err |t_value |p_value 
---------------+-----------+---------+--------+--------
   Intercept   | 150.86469 |228.92349| 0.65902| 0.51871
avg_temperature| -4.09012  | 1.13606 |-3.60026| 0.00221
 avg_humidity  |  6.41306  | 2.22558 | 2.88152| 0.01036


==============
regularization
==============
type| lambda 
----+--------
none| 1.00000


===========
call_string
===========
linear_reg('"public"."_verticapy_tmp_linearregression_v_mldb_91ad5ec097b411efa8720242ac120002_"', '"public"."_verticapy_tmp_view_v_mldb_92201ee297b411efa8720242ac120002_"', '"avg_value"', '"avg_temperature", "avg_humidity"'
USING PARAMETERS optimizer='bfgs', epsilon=1e-06, max_iterations=100, regularization='none', lambda=1, alpha=0.5, fit_intercept=true)

===============
Additional Info
===============
       Name       |Value
------------------+-----
 iteration_count  |  4  
rejected_row_count|  0  
accepted_row_count| 20  
model.report("details")
value
Dep. Variable"avg_value"
ModelLinearRegression
No. Observations20.0
No. Predictors2
R-squared0.799113694213527
Adj. R-squared0.7754800111798242
F-statistic33.81249096905822
Prob (F-statistic)3.837253952408338e-07
Kurtosis-0.0457129692472424
Skewness0.893296166786592
Jarque-Bera (JB)3.65140760780652

The model seems to be good with an adjusted R2 of 77.5%, and the F-Statistic indicates that at least one of the two predictors is useful. Let’s look at the residual plot.

sm_consumption_final = model.predict(
    sm_consumption_final,
    name = "value_prediction",
)
sm_consumption_final["residual"] = sm_consumption_final["avg_value"] - sm_consumption_final["value_prediction"]
sm_consumption_final.scatter(["avg_value", "residual"])

Looking at the residual plot, we can see that the error variance varies by quite a bit. A possible suspect might be heteroscedasticity. Let’s verify our hypothesis using a Breusch-Pagan test.

from verticapy.machine_learning.model_selection.statistical_tests import het_breuschpagan

het_breuschpagan(sm_consumption_final, "residual", predictors)
Out[27]: 
(6.066154825831241,
 0.04816717950866987,
 3.700508752254135,
 0.04632851414387972)

The p-value is 4.81% and sits around the 5% threshold, so we can’t really draw any conclusions.

Let’s look at the entire regression report.

model.report()
value
explained_variance0.799113694213527
max_error64.4503700445752
median_absolute_error13.1054316247273
mean_absolute_error20.9034976459432
mean_squared_error734.33259460088
root_mean_squared_error27.0985718184719
r20.799113694213527
r2_adj0.775480011179824
aic140.604241042862
bic140.966437863524

Our model is very good; its median absolute error is around 13kWh. With this model, we can make predictions about the energy consumption of households per region. If the usage exceeds what the model predicts, we can raise an alert and respond, for example, by regulating the electricity distributed to the region.

Conclusion

We’ve solved our problem in a Pandas-like way, all without ever loading data into memory!