In [1]:
import numpy as np
import pandas as pd
from os.path import join

from pylab import rcParams
import matplotlib.pyplot as plt
%matplotlib inline
rcParams['figure.figsize'] = (16, 8)

import nilmtk
from nilmtk import DataSet, TimeFrame, MeterGroup, HDFDataStore
from nilmtk.disaggregate import CombinatorialOptimisation
from nilmtk.utils import print_dict
from nilmtk.metrics import f1_score
import seaborn as sns
sns.set_palette("Set3", n_colors=12)


import warnings
warnings.filterwarnings("ignore")

Demo of NILMTK v0.2 for BuildSys 2014

Downloading data

The full data set can be downloaded from the remote WikiEnergy database. The credentials are omitted here for security reasons.


In [2]:
# download_wikienergy(database_username, database_password, hdf_filename)

Loading data


In [3]:
data_dir = '/home/nipun/Downloads/'
we = DataSet(join(data_dir, 'wikienergy.h5'))
print('loaded ' + str(len(we.buildings)) + ' buildings')


loaded 239 buildings

Examine dataset metadata


In [4]:
print_dict(we.metadata)


Examine metadata for a single house


In [5]:
building_number = 11
print_dict(we.buildings[building_number].metadata)


  • instance: 11
  • dataset: WikiEnergy
  • original_name: 434

Examine sub-metered appliances


In [6]:
elec = we.buildings[building_number].elec
elec.appliances


Out[6]:
[Appliance(type='fridge', instance=1),
 Appliance(type='dish washer', instance=1),
 Appliance(type='electric water heating appliance', instance=1),
 Appliance(type='spin dryer', instance=1),
 Appliance(type='electric furnace', instance=1),
 Appliance(type='sockets', instance=1),
 Appliance(type='sockets', instance=2),
 Appliance(type='air conditioner', instance=1),
 Appliance(type='sockets', instance=3),
 Appliance(type='sockets', instance=4)]

Wiring hierarchy of meters


In [7]:
elec.meters[1].when_on().next().head(100)


Out[7]:
localminute
2014-02-01 00:00:00-06:00    False
2014-02-01 00:01:00-06:00    False
2014-02-01 00:02:00-06:00    False
2014-02-01 00:03:00-06:00    False
2014-02-01 00:04:00-06:00    False
2014-02-01 00:05:00-06:00    False
2014-02-01 00:06:00-06:00    False
2014-02-01 00:07:00-06:00    False
2014-02-01 00:08:00-06:00    False
2014-02-01 00:09:00-06:00    False
2014-02-01 00:10:00-06:00    False
2014-02-01 00:11:00-06:00    False
2014-02-01 00:12:00-06:00    False
2014-02-01 00:13:00-06:00    False
2014-02-01 00:14:00-06:00    False
...
2014-02-01 01:25:00-06:00    False
2014-02-01 01:26:00-06:00    False
2014-02-01 01:27:00-06:00    False
2014-02-01 01:28:00-06:00    False
2014-02-01 01:29:00-06:00    False
2014-02-01 01:30:00-06:00    False
2014-02-01 01:31:00-06:00    False
2014-02-01 01:32:00-06:00    False
2014-02-01 01:33:00-06:00    False
2014-02-01 01:34:00-06:00    False
2014-02-01 01:35:00-06:00    False
2014-02-01 01:36:00-06:00    False
2014-02-01 01:37:00-06:00    False
2014-02-01 01:38:00-06:00    False
2014-02-01 01:39:00-06:00    False
Name: (power, active), Length: 100

In [8]:
we.store.window = TimeFrame(start='2014-04-01 00:00:00-05:00', end='2014-04-05 00:00:00-05:00')
#elec.plot();

Select all fridges


In [9]:
sns.set_palette("Set3", n_colors=12)
elec.plot_when_on(on_power_threshold = 40)


Out[9]:
<matplotlib.axes.AxesSubplot at 0x7f10d972c610>

In [10]:
for meter in elec.meters:
    meter.plot_lag(10)
    plt.title(meter.appliance_label())



In [11]:
from pandas.tools.plotting import autocorrelation_plot

In [29]:
autocorrelation_plot(elec.meters[9].power_series().next())


Out[29]:
<matplotlib.axes.AxesSubplot at 0x7f558a468e10>

In [10]:
elec.mains().plot_spectrum()


Out[10]:
<matplotlib.axes.AxesSubplot at 0x7fb4511b26d0>

In [11]:
elec.mains().plot_autocorrelation();


Here
here tooo
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-11-14c91ee180b8> in <module>()
----> 1 elec.mains().plot_autocorrelation();

/home/nipun/git/nilmtk/nilmtk/elecmeter.py in plot_autocorrelation(self)
    391         for power in self.power_series_all_data():
    392             print("here tooo")
--> 393             autocorrelation_plot(power, ax = ax)
    394             print("wwww")
    395         return ax

/home/nipun/anaconda/lib/python2.7/site-packages/pandas/tools/plotting.pyc in autocorrelation_plot(series, ax, **kwds)
    722     """
    723     import matplotlib.pyplot as plt
--> 724     n = len(series)
    725     data = np.asarray(series)
    726     if ax is None:

TypeError: object of type 'numpy.float64' has no len()

In [37]:
meter.metadata.get('device').get('sample_period')


Out[37]:
60

In [29]:
fig, ax = plt.subplots()
for i, power in enumerate(elec.meters[9].power_series()):
    print(i)
    lag_plot(power, ax = ax)


0
1
2
3
4
5

In [17]:
lag_plot(elec.power_series().next())


Out[17]:
<matplotlib.axes.AxesSubplot at 0x7fd7b83d81d0>

In [15]:
autocorrelation_plot(elec.power_series().next())


Out[15]:
<matplotlib.axes.AxesSubplot at 0x7f453522d910>

In [16]:
elec.meters[1].plot_autocorrelation()

Proportion of energy per fridge

The energy consumed by each appliance can be expressed as a proportion of the household's total energy. Here we find the range of proportions for each fridge.


In [10]:
# Select a subset of fridges, otherwise the computation takes a long time
fridges_restricted = MeterGroup(fridges.meters[:5])

proportion_per_fridge = fridges_restricted.proportion_of_upstream_total_per_meter()


Using cached result.
Using cached result.
Calculating energy for column ('power', 'active')
Using cached result.
1/5 ElecMeter(instance=18, building=60, dataset='WikiEnergy', appliances=[Appliance(type='fridge', instance=1)]) = 0.049Using cached result.
Using cached result.
Using cached result.
2/5 ElecMeter(instance=14, building=61, dataset='WikiEnergy', appliances=[Appliance(type='fridge', instance=1)]) = 0.097Using cached result.
Using cached result.
Calculating energy for column ('power', 'active')
Using cached result.
3/5 ElecMeter(instance=8, building=63, dataset='WikiEnergy', appliances=[Appliance(type='fridge', instance=1)]) = 0.000Using cached result.
Using cached result.
Using cached result.
4/5 ElecMeter(instance=6, building=64, dataset='WikiEnergy', appliances=[Appliance(type='fridge', instance=1)]) = 0.096Using cached result.
Using cached result.
Calculating energy for column ('power', 'active')
Using cached result.
5/5 ElecMeter(instance=16, building=66, dataset='WikiEnergy', appliances=[Appliance(type='fridge', instance=1)]) = 0.083

In [11]:
proportion_per_fridge.plot(kind='bar');
plt.title('fridge energy as proportion of total building energy');
plt.ylabel('proportion');
plt.xlabel('Fridge (<appliance instance>, <building instance>, <dataset name>)');



In [12]:
# How much energy does the largest-consuming fridge consume in kWh?
fridges.select(building=61).total_energy()


Using cached result.
Out[12]:
active    79.120667
dtype: float64

In [13]:
fridges.select(building=61).plot();


Daily energy consumption across fridges in WikiEnergy data set


In [14]:
fridges_restricted = MeterGroup(fridges.meters[:20])
daily_energy = pd.DataFrame([meter.average_energy_per_period(offset_alias='D') 
                             for meter in fridges_restricted.meters])

daily_energy.plot(kind='hist');
plt.title('Histogram of daily fridge energy');
plt.xlabel('energy (kWh)');
plt.ylabel('occurences');
plt.legend().set_visible(False)


Using cached result.
Calculating energy for column ('power', 'active')
Using cached result.
Using cached result.
Using cached result.
Calculating energy for column ('power', 'active')
Using cached result.
Using cached result.
Using cached result.
Calculating energy for column ('power', 'active')
Using cached result.
Using cached result.
Using cached result.
Using cached result.
Using cached result.
Using cached result.
Using cached result.
Using cached result.
Using cached result.
Using cached result.
Using cached result.
Using cached result.
Using cached result.
Using cached result.
Using cached result.
Using cached result.
Using cached result.
Using cached result.
Using cached result.
Using cached result.
Using cached result.
Using cached result.
Using cached result.
Using cached result.
Using cached result.
Using cached result.
Using cached result.
Using cached result.
Using cached result.
Using cached result.

Plot sub-metered data for a single day


In [15]:
we.store.window = TimeFrame(start='2014-04-01 00:00:00-05:00', end='2014-04-03 00:00:00-05:00')
elec.plot();



In [19]:
elec.plot_when_on()


Out[19]:
<matplotlib.axes.AxesSubplot at 0x7fed42260910>

Plot fraction of energy consumption of each appliance


In [15]:
fraction = elec.submeters().fraction_per_meter().dropna()


1/10 ElecMeter(instance=2, building=11, dataset='WikiEnergy', appliances=[Appliance(type='air conditioner', instance=1)])Using cached result.
2/10 ElecMeter(instance=3, building=11, dataset='WikiEnergy', appliances=[Appliance(type='sockets', instance=1)])Using cached result.
3/10 ElecMeter(instance=4, building=11, dataset='WikiEnergy', appliances=[Appliance(type='sockets', instance=2)])Using cached result.
4/10 ElecMeter(instance=5, building=11, dataset='WikiEnergy', appliances=[Appliance(type='dish washer', instance=1)])Using cached result.
5/10 ElecMeter(instance=6, building=11, dataset='WikiEnergy', appliances=[Appliance(type='spin dryer', instance=1)])Using cached result.
6/10 ElecMeter(instance=7, building=11, dataset='WikiEnergy', appliances=[Appliance(type='electric furnace', instance=1)])Using cached result.
7/10 ElecMeter(instance=8, building=11, dataset='WikiEnergy', appliances=[Appliance(type='sockets', instance=3)])Using cached result.
8/10 ElecMeter(instance=9, building=11, dataset='WikiEnergy', appliances=[Appliance(type='sockets', instance=4)])Using cached result.
9/10 ElecMeter(instance=10, building=11, dataset='WikiEnergy', appliances=[Appliance(type='fridge', instance=1)])Using cached result.
10/10 ElecMeter(instance=11, building=11, dataset='WikiEnergy', appliances=[Appliance(type='electric water heating appliance', instance=1)])Using cached result.

In [16]:
elec.clear_cache()


Removed building11/elec/cache/meter1/
Removed building11/elec/cache/meter2/
Removed building11/elec/cache/meter3/
Removed building11/elec/cache/meter4/
Removed building11/elec/cache/meter5/
Removed building11/elec/cache/meter6/
Removed building11/elec/cache/meter7/
Removed building11/elec/cache/meter8/
Removed building11/elec/cache/meter9/
Removed building11/elec/cache/meter10/
Removed building11/elec/cache/meter11/

In [17]:
elec.submeters().fraction_per_meter()


1/10 ElecMeter(instance=2, building=11, dataset='WikiEnergy', appliances=[Appliance(type='air conditioner', instance=1)])Calculating energy for column ('power', 'active')
2/10 ElecMeter(instance=3, building=11, dataset='WikiEnergy', appliances=[Appliance(type='sockets', instance=1)])Calculating energy for column ('power', 'active')
3/10 ElecMeter(instance=4, building=11, dataset='WikiEnergy', appliances=[Appliance(type='sockets', instance=2)])Calculating energy for column ('power', 'active')
4/10 ElecMeter(instance=5, building=11, dataset='WikiEnergy', appliances=[Appliance(type='dish washer', instance=1)])Calculating energy for column ('power', 'active')
5/10 ElecMeter(instance=6, building=11, dataset='WikiEnergy', appliances=[Appliance(type='spin dryer', instance=1)])Calculating energy for column ('power', 'active')
6/10 ElecMeter(instance=7, building=11, dataset='WikiEnergy', appliances=[Appliance(type='electric furnace', instance=1)])Calculating energy for column ('power', 'active')
7/10 ElecMeter(instance=8, building=11, dataset='WikiEnergy', appliances=[Appliance(type='sockets', instance=3)])Calculating energy for column ('power', 'active')
8/10 ElecMeter(instance=9, building=11, dataset='WikiEnergy', appliances=[Appliance(type='sockets', instance=4)])Calculating energy for column ('power', 'active')
9/10 ElecMeter(instance=10, building=11, dataset='WikiEnergy', appliances=[Appliance(type='fridge', instance=1)])Calculating energy for column ('power', 'active')
10/10 ElecMeter(instance=11, building=11, dataset='WikiEnergy', appliances=[Appliance(type='electric water heating appliance', instance=1)])Calculating energy for column ('power', 'active')
Out[17]:
2                            NaN
3                            NaN
4                            NaN
5                            NaN
6                            NaN
7                            NaN
8                            NaN
9                            NaN
10                           NaN
11                           NaN
(2, 11, WikiEnergy)     0.541636
(3, 11, WikiEnergy)     0.046624
(4, 11, WikiEnergy)     0.011947
(5, 11, WikiEnergy)     0.053094
(6, 11, WikiEnergy)     0.007034
(7, 11, WikiEnergy)     0.127455
(8, 11, WikiEnergy)     0.024780
(9, 11, WikiEnergy)     0.058938
(10, 11, WikiEnergy)    0.121804
(11, 11, WikiEnergy)    0.006687
dtype: float64

In [18]:
elec.submeters().fraction_per_meter()


1/10 ElecMeter(instance=2, building=11, dataset='WikiEnergy', appliances=[Appliance(type='air conditioner', instance=1)])Using cached result.
2/10 ElecMeter(instance=3, building=11, dataset='WikiEnergy', appliances=[Appliance(type='sockets', instance=1)])Using cached result.
3/10 ElecMeter(instance=4, building=11, dataset='WikiEnergy', appliances=[Appliance(type='sockets', instance=2)])Using cached result.
4/10 ElecMeter(instance=5, building=11, dataset='WikiEnergy', appliances=[Appliance(type='dish washer', instance=1)])Using cached result.
5/10 ElecMeter(instance=6, building=11, dataset='WikiEnergy', appliances=[Appliance(type='spin dryer', instance=1)])Using cached result.
6/10 ElecMeter(instance=7, building=11, dataset='WikiEnergy', appliances=[Appliance(type='electric furnace', instance=1)])Using cached result.
7/10 ElecMeter(instance=8, building=11, dataset='WikiEnergy', appliances=[Appliance(type='sockets', instance=3)])Using cached result.
8/10 ElecMeter(instance=9, building=11, dataset='WikiEnergy', appliances=[Appliance(type='sockets', instance=4)])Using cached result.
9/10 ElecMeter(instance=10, building=11, dataset='WikiEnergy', appliances=[Appliance(type='fridge', instance=1)])Using cached result.
10/10 ElecMeter(instance=11, building=11, dataset='WikiEnergy', appliances=[Appliance(type='electric water heating appliance', instance=1)])Using cached result.
Out[18]:
2                            NaN
3                            NaN
4                            NaN
5                            NaN
6                            NaN
7                            NaN
8                            NaN
9                            NaN
10                           NaN
11                           NaN
(2, 11, WikiEnergy)     0.541636
(3, 11, WikiEnergy)     0.046624
(4, 11, WikiEnergy)     0.011947
(5, 11, WikiEnergy)     0.053094
(6, 11, WikiEnergy)     0.007034
(7, 11, WikiEnergy)     0.127455
(8, 11, WikiEnergy)     0.024780
(9, 11, WikiEnergy)     0.058938
(10, 11, WikiEnergy)    0.121804
(11, 11, WikiEnergy)    0.006687
dtype: float64

In [19]:
# Create convenient labels
labels = elec.get_appliance_labels(fraction.index)
plt.figure(figsize=(8,8))
fraction.plot(kind='pie', labels=labels);


Select meters on the basic of appliance category


In [20]:
elec.select_using_appliances(category='heating')


Out[20]:
MeterGroup(meters=
  ElecMeter(instance=7, building=11, dataset='WikiEnergy', appliances=[Appliance(type='electric furnace', instance=1)])
  ElecMeter(instance=11, building=11, dataset='WikiEnergy', appliances=[Appliance(type='electric water heating appliance', instance=1)])
)

In [21]:
# Find all appliances with a particular type of motor
elec.select_using_appliances(category='single-phase induction motor')


Out[21]:
MeterGroup(meters=
  ElecMeter(instance=2, building=11, dataset='WikiEnergy', appliances=[Appliance(type='air conditioner', instance=1)])
  ElecMeter(instance=5, building=11, dataset='WikiEnergy', appliances=[Appliance(type='dish washer', instance=1)])
  ElecMeter(instance=6, building=11, dataset='WikiEnergy', appliances=[Appliance(type='spin dryer', instance=1)])
  ElecMeter(instance=7, building=11, dataset='WikiEnergy', appliances=[Appliance(type='electric furnace', instance=1)])
  ElecMeter(instance=10, building=11, dataset='WikiEnergy', appliances=[Appliance(type='fridge', instance=1)])
)

Training and disaggregation


In [22]:
# Train
co = CombinatorialOptimisation()
co.train(elec)


Training model for submeter 'ElecMeter(instance=2, building=11, dataset='WikiEnergy', appliances=[Appliance(type='air conditioner', instance=1)])'
Training model for submeter 'ElecMeter(instance=3, building=11, dataset='WikiEnergy', appliances=[Appliance(type='sockets', instance=1)])'
Training model for submeter 'ElecMeter(instance=4, building=11, dataset='WikiEnergy', appliances=[Appliance(type='sockets', instance=2)])'
Training model for submeter 'ElecMeter(instance=5, building=11, dataset='WikiEnergy', appliances=[Appliance(type='dish washer', instance=1)])'
Training model for submeter 'ElecMeter(instance=6, building=11, dataset='WikiEnergy', appliances=[Appliance(type='spin dryer', instance=1)])'
Training model for submeter 'ElecMeter(instance=7, building=11, dataset='WikiEnergy', appliances=[Appliance(type='electric furnace', instance=1)])'
Training model for submeter 'ElecMeter(instance=8, building=11, dataset='WikiEnergy', appliances=[Appliance(type='sockets', instance=3)])'
Training model for submeter 'ElecMeter(instance=9, building=11, dataset='WikiEnergy', appliances=[Appliance(type='sockets', instance=4)])'
Training model for submeter 'ElecMeter(instance=10, building=11, dataset='WikiEnergy', appliances=[Appliance(type='fridge', instance=1)])'
Training model for submeter 'ElecMeter(instance=11, building=11, dataset='WikiEnergy', appliances=[Appliance(type='electric water heating appliance', instance=1)])'
Done training!

In [23]:
for model in co.model:
    print_dict(model)


  • states: [ 0 826 2944]
  • training_metadata: ElecMeter(instance=2, building=11, dataset='WikiEnergy', appliances=[Appliance(type='air conditioner', instance=1)])
  • states: [ 0 12 73]
  • training_metadata: ElecMeter(instance=3, building=11, dataset='WikiEnergy', appliances=[Appliance(type='sockets', instance=1)])
  • states: [ 0 11 12]
  • training_metadata: ElecMeter(instance=4, building=11, dataset='WikiEnergy', appliances=[Appliance(type='sockets', instance=2)])
  • states: [ 0 198 1025]
  • training_metadata: ElecMeter(instance=5, building=11, dataset='WikiEnergy', appliances=[Appliance(type='dish washer', instance=1)])
  • states: [0]
  • training_metadata: ElecMeter(instance=6, building=11, dataset='WikiEnergy', appliances=[Appliance(type='spin dryer', instance=1)])
  • states: [ 0 15 524]
  • training_metadata: ElecMeter(instance=7, building=11, dataset='WikiEnergy', appliances=[Appliance(type='electric furnace', instance=1)])
  • states: [ 0 35 800]
  • training_metadata: ElecMeter(instance=8, building=11, dataset='WikiEnergy', appliances=[Appliance(type='sockets', instance=3)])
  • states: [ 0 49 52]
  • training_metadata: ElecMeter(instance=9, building=11, dataset='WikiEnergy', appliances=[Appliance(type='sockets', instance=4)])
  • states: [ 0 139 465]
  • training_metadata: ElecMeter(instance=10, building=11, dataset='WikiEnergy', appliances=[Appliance(type='fridge', instance=1)])
  • states: [ 0 17 34]
  • training_metadata: ElecMeter(instance=11, building=11, dataset='WikiEnergy', appliances=[Appliance(type='electric water heating appliance', instance=1)])

In [24]:
# Disaggregate
disag_filename = join(data_dir, 'wikienergy-disag.h5')
output = HDFDataStore(disag_filename, 'w')
co.disaggregate(elec.mains(), output)
output.close()


vampire_power = 290.0 watts
Estimating power demand for 'ElecMeter(instance=2, building=11, dataset='WikiEnergy', appliances=[Appliance(type='air conditioner', instance=1)])'
Estimating power demand for 'ElecMeter(instance=3, building=11, dataset='WikiEnergy', appliances=[Appliance(type='sockets', instance=1)])'
Estimating power demand for 'ElecMeter(instance=4, building=11, dataset='WikiEnergy', appliances=[Appliance(type='sockets', instance=2)])'
Estimating power demand for 'ElecMeter(instance=5, building=11, dataset='WikiEnergy', appliances=[Appliance(type='dish washer', instance=1)])'
Estimating power demand for 'ElecMeter(instance=6, building=11, dataset='WikiEnergy', appliances=[Appliance(type='spin dryer', instance=1)])'
Estimating power demand for 'ElecMeter(instance=7, building=11, dataset='WikiEnergy', appliances=[Appliance(type='electric furnace', instance=1)])'
Estimating power demand for 'ElecMeter(instance=8, building=11, dataset='WikiEnergy', appliances=[Appliance(type='sockets', instance=3)])'
Estimating power demand for 'ElecMeter(instance=9, building=11, dataset='WikiEnergy', appliances=[Appliance(type='sockets', instance=4)])'
Estimating power demand for 'ElecMeter(instance=10, building=11, dataset='WikiEnergy', appliances=[Appliance(type='fridge', instance=1)])'
Estimating power demand for 'ElecMeter(instance=11, building=11, dataset='WikiEnergy', appliances=[Appliance(type='electric water heating appliance', instance=1)])'

Examine disaggregated data


In [25]:
disag = DataSet(disag_filename)
disag_elec = disag.buildings[building_number].elec
disag_elec.plot()
disag.store.close()


Calculate accuracy of disaggregation


In [26]:
disag = DataSet(disag_filename)
disag_elec = disag.buildings[building_number].elec

f1 = f1_score(disag_elec, elec)
f1.index = disag_elec.get_appliance_labels(f1.index)
f1.plot(kind='bar')
plt.xlabel('appliance');
plt.ylabel('f-score');

disag.store.close()



In [26]: