Solucionar problemas instalando nilmtk-contrib


Nilmtk-contrib es un repositorio de contribuciones de la comunidad para NILMTK que permite agregar nuevas funcionalidades, modelos de aprendizaje automático y algoritmos de desagregación de energía. Dado que el desarrollo del NILMTK principal ha sido más lento en los últimos años, nilmtk-contrib permite a los investigadores y desarrolladores mejorar la herramienta sin depender de actualizaciones en el repositorio principal.

Características de nilmtk-contrib

  1. Nuevos Algoritmos de Desagregación
    • Contiene implementaciones de modelos avanzados basados en redes neuronales, como Sequence-to-Sequence y Variational Autoencoders.
    • Se han añadido métodos híbridos que combinan enfoques basados en descomposición de señales y aprendizaje profundo.
  2. Soporte para Nuevos Datasets
    • Extiende la compatibilidad con bases de datos de consumo eléctrico no incluidas en NILMTK.
    • Simplifica la conversión de datos desde formatos comunes como CSV a HDF5, que es el formato utilizado por NILMTK.
  3. Mayor Flexibilidad y Mantenibilidad
    • Permite a los desarrolladores probar nuevas ideas sin modificar el código base del NILMTK original.
    • Se puede instalar y utilizar junto con NILMTK sin conflictos.

Para instalar nilmtk-contrib correctamente, debes cumplir con los requisitos de versiones específicas de Python y dependencias.

Requisitos clave

PaqueteVersión requeridaCompatibilidad con Python
NILMTK>=0.4Python 3.7 (recomendado)
scikit-learn>=0.21Python 3.5-3.7
Keras>=2.2.4Python 3.5+
cvxpy>=1.0.0Python >=3.7 (para cvxpy<=1.0.0)

Guia paso a paso para instalar nilmtk-contrib sin conflictos

Los pasos ajustados para crear un entorno limpio, instalando las versiones de las librerías necesarias y evitando los errores tipicos:

1. Crear y preparar el entorno virtual

Primero, elimina cualquier entorno anterior si es necesario y luego crea uno nuevo:

# Verificar los entornos existentes
conda env list

# Eliminar el entorno 'nilm' si ya existe
conda env remove --name nilm

# Limpiar cache
conda clean --all

Python 3.7 es la versión más estable que es usada para estas dependencias y la que los creadores de NILMTK recomiendas, luego, lo ideal es crear el entorno limpio con esa versión:

# Crear el entorno 'nilm' con Python 3.7
conda create -n nilm python=3.7 -y

# Activar el entorno recién creado
conda activate nilm

2. Instalar numpy compatible

Instalar una versión específica de numpy para asegurar la compatibilidad con NILMTK:

pip install numpy==1.19.5

3. Agregar canales de Conda

Para asegurar que las dependencias necesarias se encuentren:

conda config --add channels conda-forge
conda config --add channels nilmtk

4. Instalar nilmtk

Instala la versión compatible de NILMTK:

conda install -c nilmtk nilmtk=0.4.3 -y

5. Instalar matplotlib compatible

La versión de matplotlib requerida por NILMTK 0.4.3 es algo restrictiva. Debes instalar matplotlib-base primero:

# Instalar matplotlib-base y matplotlib compatibles
conda install matplotlib-base=3.1.3 matplotlib=3.1.3 -y

6. Instalar TensorFlow compatible

Instalar una versión de TensorFlow compatible con las bibliotecas:

pip install tensorflow==1.14.0

7. Instalar nilm_metadata

Instalar el paquete nilm_metadata desde GitHub:

pip install git+https://github.com/nilmtk/nilm_metadata

8. Instalar nilmtk-contrib

La instalación de nilmtk-contrib podría fallar debido a la falta de detección de la instalación de NILMTK por parte de pip. La solución es instalar nilmtk-contrib sin depender de las bibliotecas que necesita verificar:

pip install --no-deps git+https://github.com/nilmtk/nilmtk-contrib

Alternativa (si el paso anterior no funciona ): Si el paso anterior no funciona, puedes clonar el repositorio y hacer la instalación manualmente:

git clone https://github.com/nilmtk/nilmtk-contrib.git
cd nilmtk-contrib
pip install --no-deps .

9. Instalar otras dependencias necesarias

Es posible que necesites instalar otras dependencias, como cvxpy y protobuf:

pip install protobuf==3.20.*
pip install cvxpy==1.1.13

10. Crear archivo parche.py (muy importante)

Si ejecutamos algo que incluya el modulos niml_contrib con la instalacion actual, lo normal es tener con BinaryCrossentropy y MeanSquaredError. Si se presenta el error ImportError: cannot import name 'BinaryCrossentropy' from 'keras.losses', podriamos editar el archivo correspondiente (rnn_attention_classification.py) para reemplazar las importaciones incorrectas de Keras. Es decir en lugar de:

from keras.losses import BinaryCrossentropy, MeanSquaredError

Usar las funciones personalizadas para estas pérdidas:

from keras import backend as K

def BinaryCrossentropy():
def loss(y_true, y_pred):
return K.binary_crossentropy(y_true, y_pred)
return loss

def MeanSquaredError():
def loss(y_true, y_pred):
return K.mean(K.square(y_pred - y_true), axis=-1)
return loss

El problema es que si tocamos ficheros de la librería nos va a fallar el kernel, así que lo mejor es hacerlo lo mismo desde un parche (lo cual en el argot se llama monkey patche), que deberemos guardar en nuestro directorio de trabajo.

El contenido final del parche, por ejemplo que nombraremos como «parche.py» , es el siguiente:

import keras.losses
import keras.layers

# Parches para evitar errores de importación con versiones antiguas de Keras
if not hasattr(keras.losses, 'BinaryCrossentropy'):
    def BinaryCrossentropy(*args, **kwargs): pass
    keras.losses.BinaryCrossentropy = BinaryCrossentropy

if not hasattr(keras.losses, 'MeanSquaredError'):
    def MeanSquaredError(*args, **kwargs): pass
    keras.losses.MeanSquaredError = MeanSquaredError

if not hasattr(keras.layers, 'MultiHeadAttention'):
    class MultiHeadAttention:
        def __init__(self, *args, **kwargs): pass
        def __call__(self, *args, **kwargs): return self
    keras.layers.MultiHeadAttention = MultiHeadAttention

if not hasattr(keras.layers, 'LayerNormalization'):
    class LayerNormalization:
        def __init__(self, *args, **kwargs): pass
        def __call__(self, *args, **kwargs): return self
    keras.layers.LayerNormalization = LayerNormalization

Para usar el parche en nuestro código sin tener que tocar variables de entorno con el directorio de trabajo podemos usar este ejemplo adaptándolo a nuestra casuística particular:

import tensorflow as tf
print("TF version:", tf.__version__)

import sys
sys.path.append("D:/ruta/a/tu/directorio/del/parche")  # Asegúrate de que el parche.py esté allí

import parche  # Esto aplica los monkey patches

import nilmtk_contrib
print("nilmtk-contrib instalado correctamente")
  • El parche.py se encarga de que nilmtk_contrib no falle por capas o funciones modernas que no existen en Keras 2.2.4.
  • Si necesitas realmente usar MultiHeadAttention o BERT, requerirás migrar a TensorFlow 2.x (no recomendado si usas NILMTK 0.4.3).

11. Registrar el entorno en Jupyter (Muy recomndable)

Si deseas usar este entorno en Jupyter Notebook, regístralo como un nuevo kernel:

python -m ipykernel install --user --name nilm --display-name "Python (nilm)"

Para probar que todo ha ido bien, ejecuta este comando para confirmar que todo está instalado correctamente:

python -c «import nilmtk; import nilmtk_contrib; print(‘Éxito’)»

12. Salir del entorno

Cuando termines de trabajar en el entorno, puedes desactivarlo:

conda deactivate

13. Verificar el entorno

Finalmente, asegúrate de que el entorno esté configurado correctamente:

conda env list

Con estos pasos, tu entorno limpio debería estar correctamente configurado para trabajar con NILMTK, nilmtk-contrib, y otras bibliotecas necesarias. Si tienes algún problema en el proceso, seria recomendable empezar nuevamente desde el principio porque esta guia ha sido contrasatada y deberia de funcionar.

Módulos que puede que se necesite instalar si hay errores ( lo anexo simplemente por curiosidad pero no seran necesarios con los pasos anteriores):

1. Instalar Keras y TensorFlow compatibles

Para evitar conflictos con keras.optimizers, usa:

pip install tensorflow==2.5.0 keras==2.4.3 h5py==3.1.0

2. Instalar cvxpy 1.0.0 (versión compatible)

cvxpy 1.0.0 funcionaba con Python 3.7 pero ahora no es posible:

pip install cvxpy==1.0.0

El error ocurre porque CVXPY 1.0.0 no existe en PyPI, y las versiones disponibles requieren Python ≥3.8. Para resolverlo en tu entorno nilmtk-env (Python 3.7), sigue estos pasos:

3. Instalar CVXPY 1.3.4 (última versión compatible con Python 3.7):

pip install cvxpy==1.3.4 numpy==1.19.5 scipy==1.6.3

Verificar instalación:

python -c "import cvxpy; print(cvxpy.__version__)"
# Debe mostrar: 1.3.4

Resolución de otros conflictos comunes

ErrorSolución
ImportError: cannot import name 'SGD'Asegúrate de usar tensorflow.keras.optimizers en lugar de keras.optimizers.
ModuleNotFoundError: No module named 'tensorflow'Revisa que tensorflow==2.5.0 esté instalado.
numpy.ufunc size changedFija numpy==1.19.5 y evita actualizaciones automáticas.

Notas adicionales

  • GPU: Si tienes una tarjeta NVIDIA, instala CUDA 11.2 y cuDNN 8.1.0 para acelerar el entrenamiento.
  • Entornos alternativos: Si persisten errores, clona los repositorios manualmente y configura el PYTHONPATH:bashgit clone https://github.com/nilmtk/nilm_metadata.git git clone https://github.com/nilmtk/nilmtk.git git clone https://github.com/nilmtk/nilmtk-contrib.git set PYTHONPATH=%PYTHONPATH%;C:\ruta\a\nilm_metadata;C:\ruta\a\nilmtk;C:\ruta\a\nilmtk-contrib

Con estos pasos, nilmtk-contrib debería funcionar sin conflictos en Windows.

Ejemplo de Uso

Después de instalarlo, puedes importar y utilizar algoritmos de desagregación avanzados como:

from nilmtk_contrib.disaggregate import Seq2Point

model = Seq2Point()
# Cargar datos y entrenar el modelo...

Conclusión

nilmtk-contrib es una excelente opción si trabajas en NILM y necesitas herramientas más actualizadas y flexibles que las que ofrece NILMTK por defecto. Es especialmente útil para investigadores que desean experimentar con nuevos modelos de desagregación energética.

2024 03 31 12 37 03 INSTALAR NILMTK EN UBUNTU Busqueda de Google y 6 paginas mas Personal  Micro

Introducción a python científico


Muchas áreas de carácter científico-técnico la adecuada elección del software y/o lenguaje de programación empleado es determinante, de cara a la potencia, versatilidad, facilidad de uso y acceso por parte de todos los usuarios en sus propios dispositivos, de manera generalizada y gratuita.

Dentro del software libre, uno de los que últimamente ha tenido una mejora sustancial, con la inclusión de potentes y versátiles nuevos módulos de cálculo simbólico (SymPy), numérico (NumPy, SciPy) y gráfico (PyPlot y Matplotlib) ha sido sin duda Python, y de ahí su vertiginosa evolución y expansión a nivel mundial, no sólo en el ámbito académico, sino también en el científico e industrial. De hecho, basta con echar un vistazo a las numerosas propuestas, tanto de comunidades de desarrolladores como de empresas privadas, surgidas a raíz de la versión de base inicial de Python, como por ejemplo IPython (interface interactivo de fácil uso, que gracias a Jupyter Notebook permite una versión HTML similar a los notebooks de Mathematica o Mapple) o Spyder (entorno integrado para cálculo científico parecido al de Matlab u Octave).

Por otro lado existen versiones completas de desarrollo, integrando Python como soporte de cálculo, pero con editores avanzados de texto para la programación y la depuración de código, ventanas de gráficos y datos, etc. La mayoría de estas plataformas integradas están disponibles para los distintos sistemas operativos Linux, MacOS X y Windows. Entre ellas cabría destacar Enthought Python Distribution (EPD), PyCharm y Anaconda CE (de Continuum Analytics).

Aunque no podamos abarcar todos los aspectos «básicos» del python científico, intentaremos en este resumen dar una idea de las principales librerías un funciones que podemos usar para NILM (Non-Intrusive Load Monitoring) sin olvidar los fundamentos de :Matplotlib y Numpy

Matplotlib: visualización con Python 

Matplotlib es una biblioteca completa para crear visualizaciones estáticas, animadas e interactivas en Python haciendo que las cosas fáciles sean fáciles y las difíciles posibles.

Nos permite crear :

  • Desarrollando gráficos de calidad de publicación con solo unas pocas líneas de código
  • Utilizando figuras interactivas que puedan hacer zoom, desplazarse, actualizar …

Personalizar

  • Tomando el control total de los estilos de línea, las propiedades de la fuente, las propiedades de los ejes …
  • Exportando e incrustando en varios formatos de archivo y entornos interactivos

Ampliar

  • Explorando la funcionalidad personalizada proporcionada por paquetes de terceros
  • Obteniendo más información sobre Matplotlib a través de los numerosos recursos de aprendizaje externos

Matplotlib es en resumen la librería de python para dibujar (equivalente al plot en matlab).

Puede encontrar mas información en el sitio oficial https://matplotlib.org/

Numpy

NumPy es una biblioteca para el lenguaje de programación Python que da soporte para crear vectores y matrices grandes multidimensionales, junto con una gran colección de funciones matemáticas de alto nivel para operar con ellas.

Numpy es pues una librería especializada para operaciones con matrices y vectores

Puede encontrar mas información en l sitio oficial https://numpy.org/

La imagen tiene un atributo ALT vacío; su nombre de archivo es image-11.png

Primeros pasos

Primero, es necesario importarlas al workspace

import numpy as np
import matplotlib.pyplot as plt

Opciones de visualizacion de matplotlib para un notebook

%matplotlib inline
plt.rcParams['figure.figsize'] = (13, 6)
plt.style.use('ggplot')

Otras importaciones:

import warnings
warnings.filterwarnings('ignore')

Crear arrays en python es muy sencillo y se puede hacer de forma nativa usando un tipo list. Sin embargo, aquí consideramos arrays del tipo numpy pues esto arrays incluyen funciones que facilitan las operaciones matemáticas y su manipulación

v=[1,2,3] # tipo list
v=np.array([1,2,3]) # array numpy
print (v)
print ("Dimensiones: " + str(v.ndim)) # numero de dimensiones
print ("Elementos: " + str(v.size)) # numero de elementos
print ("Longitud de las dimensiones: " + str(v.shape)) # longitud de cada dimensión
[1 2 3]
Dimensiones: 1
Elementos: 3
Longitud de las dimensiones: (3,)

Crear una matriz de 2 x 3:

v=np.array([[1,2,3], [4,5,6]])
print (v)
print ('Dimensiones: ' + str(v.ndim)) # numero de dimensiones
print ('Elementos: '+str(v.size)) # numero de elementos
print ('Longitud de las dimensiones: '+str(v.shape)) # longitud de cada dimensión
[[1 2 3]
 [4 5 6]]
Dimensiones: 2
Elementos: 6
Longitud de las dimensiones: (2, 3)

Crear una Matriz triple de 2 x 3 x 2 :

v=np.array([[[1,2], [3,4]],[[5,6],  [7,8]]])
print (v)
print ("Dimensiones: " + str(v.ndim)) # numero de dimensiones
print ("Elementos: "+str(v.size)) # numero de elementos
print ("Longitud de las dimensiones: "+str(v.shape) )# longitud de cada dimensión

[[[1 2], 
      [3 4]],

 [[5 6], 
      [7 8]]]
Dimensiones: 3
Elementos: 8
Longitud de las dimensiones: (2, 2, 2)

Utilizamos la función reshape para redimensionar los arrays

1 dimension

print (v.reshape(8,))
[1 2 3 4 5 6 7 8]

2 dimensiones

print (v.reshape(2,4))
[[1 2 3 4]
 [5 6 7 8]]

Matriz Identidad de 5×5

print (np.identity(5))
[[1. 0. 0. 0. 0.]
 [0. 1. 0. 0. 0.]
 [0. 0. 1. 0. 0.]
 [0. 0. 0. 1. 0.]
 [0. 0. 0. 0. 1.]]

Matriz de unos de 5×5

print ( np.ones([5,5]))
[[1. 1. 1. 1. 1.]
 [1. 1. 1. 1. 1.]
 [1. 1. 1. 1. 1.]
 [1. 1. 1. 1. 1.]
 [1. 1. 1. 1. 1.]]

Matriz de ceros de 5×5:

print (np.zeros([5,5]))
[[0. 0. 0. 0. 0.]
 [0. 0. 0. 0. 0.]
 [0. 0. 0. 0. 0.]
 [0. 0. 0. 0. 0.]
 [0. 0. 0. 0. 0.]]

Las operaciones por definición son elementwise

a=np.arange(5)
b=10*np.ones(5)
print ("vector a: "+str(a))
print ("vector b: "+str(b))
print ("suma b+a: "+str(b-a))
print ("resta b-a: "+str(b+a))
print ("producto b*a: "+str(b*a))
vector a: [0 1 2 3 4]
vector b: [10. 10. 10. 10. 10.]
suma b+a: [10.  9.  8.  7.  6.]
resta b-a: [10. 11. 12. 13. 14.]
producto b*a: [ 0. 10. 20. 30. 40.]

El producto de los vectores es:

a.dot(b)
100.0

Para las matrices tenemos que:

a=np.identity(3)
b=np.array([[1,2,3],[4,5,6],[7,8,9]])
print ("matriz a:\n"+str(a))
print ("matriz b:\n"+str(b))
print ("producto a*b:\n"+str(a.dot(b)))
print ("producto elementwise a.*b:\n"+str(a*b))
matriz a:
[[1. 0. 0.]
 [0. 1. 0.]
 [0. 0. 1.]]
matriz b:
[[1 2 3]
 [4 5 6]
 [7 8 9]]
producto a*b:
[[1. 2. 3.]
 [4. 5. 6.]
 [7. 8. 9.]]
producto elementwise a.*b:
[[1. 0. 0.]
 [0. 5. 0.]
 [0. 0. 9.]]

Vector formado por un rango de valores:

print ("De 0 a 10: " + str(np.arange(10)))
print ("De 10 a 20 de paso 0.5: "+str(np.arange(10,20,0.5)))
De 0 a 10: [0 1 2 3 4 5 6 7 8 9]
De 10 a 20 de paso 0.5: [10.  10.5 11.  11.5 12.  12.5 13.  13.5 14.  14.5 15.  15.5 16.  16.5
 17.  17.5 18.  18.5 19.  19.5]

Función linspace:

np.linspace(0,2*np.pi,10) # de 0 a 2*pi en 10 puntos equidistantes
array([0.        , 0.6981317 , 1.3962634 , 2.0943951 , 2.7925268 ,
       3.4906585 , 4.1887902 , 4.88692191, 5.58505361, 6.28318531])

función random:

np.random.rand(10)
array([0.63623588, 0.83924558, 0.35833155, 0.33835148, 0.53247758,
       0.0950348 , 0.2805706 , 0.47285484, 0.8696919 , 0.78361161])

Dibujar una función seno

t = np.arange(0.0, 2.0, 0.01)
s = np.sin(2*np.pi*t)
plt.plot(t, s)
plt.xlabel('time (s)')
plt.ylabel('voltage (mV)')
plt.title('Sinusoidal')
plt.grid(True)

Dibujar una función chirp

x=np.linspace(0,3*np.pi,500)
plt.plot(x,np.sin(x**2))
plt.title("A simple chirp")
Text(0.5, 1.0, 'A simple chirp')

Definir una función en Python

En python, las funciones pueden estar definidas en cualquier parte pero siempre antes de su llamada. En python, las anidaciones (bucles, if conditions, functions, etc.) se realizan mediante indentación, no existe el statement end. Las funciones se definen así:

def funcion_suma(x): 
    suma=0
    for i in x: 
        suma=suma+i
    return suma 
v=np.arange(10)
print (funcion_suma(v))
45

Aunque, como hemos dicho antes, numpy facilita las operaciones matemáticas y ya incluye una serie de operaciones:

print (v.sum())
print (v.cumsum())
print (v.mean())
45
[ 0  1  3  6 10 15 21 28 36 45]
4.5

Para saber más sobre numpy:

https://docs.scipy.org/doc/numpy-dev/user/quickstart.html

http://www.sam.math.ethz.ch/~raoulb/teaching/PythonTutorial/intro_numpy.html

(O simplemente «googleando»: numpy tutorial)

Pandas

Pandas (Python Data Analysis Library) es una librería de python para el análisis y manipulación de una gran cantidad de datos. También facilita el uso de «timeseries»

La llamada a la librería es:

import pandas as pd

Dado un archivo csv, la función read_csv carga los datos en un dataframe

# El parámetro parse_dates indica a pandas que al cargar este csv la primera columna [0] es de tipo datetime
df=pd.read_csv('data/events.csv',parse_dates=[0])

Las primeras N filas del dataFrame se puede visualizar de la siguiente forma

N=4
df.head(N)
timestamplabelphase
02011-10-20 12:22:01.473111A
12011-10-20 12:37:40.507111A
22011-10-20 13:23:55.390111A
32011-10-20 13:39:08.157111A

Y las N últimas columnas

df.tail(N)
timestamplabelphase
24812011-10-27 12:57:17.079111A
24822011-10-27 13:10:45.112111A
24832011-10-27 13:54:08.862111A
24842011-10-27 14:07:21.612111A

Podemos filtar por un cierto valor

df[df.phase=='B'].head()
timestamplabelphase
122011-10-20 15:45:54.590204B
132011-10-20 15:47:31.223204B
142011-10-20 16:09:00.424204B
182011-10-20 17:42:00.657155B
192011-10-20 17:42:04.407157B

Y hacer agrupaciones

df2=df.sort_values(['label','phase']).groupby(['label','phase']).count()
df2
timestamp
labelphase
101B26
102B25
103B24
108A16
111A619
1125A1
1126A1
1127A1
1200A1
1201A1

161 rows × 1 columns

Las nuevas columnas se crean fácilmente. Compatible con numpy.

df['x']=25*np.random.rand(len(df))
df['y']=100*np.sin(2*np.pi*np.linspace(0,2*np.pi,len(df)))
df['z']=df.x+df.y
df.head(5)
timestamplabelphasexyz
02011-10-20 12:22:01.473111A0.0167760.0000000.016776
12011-10-20 12:37:40.507111A5.6400571.5892417.229298
22011-10-20 13:23:55.390111A5.6322523.1780818.810333
32011-10-20 13:39:08.157111A9.2871414.76611914.053259
42011-10-20 14:25:51.473111A9.3135696.35295215.666521

Para dibujar sólo necesitamos usar la función plot

df.z.plot()
<matplotlib.axes._subplots.AxesSubplot at 0x7f6e3ba88080>

Existen ciertas funciones predefinidas que facilitan los cálculos

df.z.cumsum().plot()
<matplotlib.axes._subplots.AxesSubplot at 0x7f6e3b801e80>

Y se pueden concatenar

# Si integramos y derivamos obtenemos la misma señal
df.z.cumsum().diff().plot()
<matplotlib.axes._subplots.AxesSubplot at 0x7f6e32625320>

Unas de las herramientas más potentes de pandas es la manipulación de timeseries

df.index=df.timestamp
df.z.plot()
<matplotlib.axes._subplots.AxesSubplot at 0x7f6e325e6518>

Podemos filtar por fechas

d1='2011-10-21'
d2='2011-10-23'
df[(df.index>d1)&(df.index<d2)].z.plot()
<matplotlib.axes._subplots.AxesSubplot at 0x7f6e325d5588>

Existe una gran flexibilidad a la hora de resamplear un dataframe

# Cada día 
df.resample('1D',how='sum')
labelxyz
timestamp
2011-10-20233182044.60316112047.56801914092.171180
2011-10-21507894364.168081-4531.116500-166.948419
2011-10-221356456971.7315141811.9787858783.710300
2011-10-231021845445.726210-4029.5292421416.196968
2011-10-24462593554.5631237284.89716310839.460286
2011-10-25525523933.715959-4712.890577-779.174618
2011-10-26590843503.958137-7682.254604-4178.296467
2011-10-27181921325.9193697454.6146868780.534055
# Cada 6 horas
df.resample('6H',how='count')
timestamplabelphasexyz
timestamp
2011-10-20 12:00:00373737373737
2011-10-20 18:00:00135135135135135135
2011-10-21 00:00:00160160160160160160
2011-10-21 06:00:00676767676767
2011-10-21 12:00:00262626262626
2011-10-21 18:00:00828282828282
2011-10-22 00:00:00242424242424
2011-10-22 06:00:00107107107107107107
2011-10-22 12:00:00215215215215215215
2011-10-22 18:00:00203203203203203203
2011-10-23 00:00:00636363636363
2011-10-23 06:00:00646464646464
2011-10-23 12:00:00737373737373
2011-10-23 18:00:00237237237237237237
2011-10-24 00:00:00363636363636
2011-10-24 06:00:00393939393939
2011-10-24 12:00:00494949494949
2011-10-24 18:00:00162162162162162162
2011-10-25 00:00:00333333333333
2011-10-25 06:00:00919191919191
2011-10-25 12:00:00373737373737
2011-10-25 18:00:00152152152152152152
2011-10-26 00:00:00232323232323
2011-10-26 06:00:00616161616161
2011-10-26 12:00:00161616161616
2011-10-26 18:00:00196196196196196196
2011-10-27 00:00:00363636363636
2011-10-27 06:00:00555555555555
2011-10-27 12:00:00666666

Para aprender más sobre pandas:

http://pandas.pydata.org/pandas-docs/stable/tutorials.html

http://pandas.pydata.org/pandas-docs/stable/10min.html

Detector de eventos

Vamos a crear un detector de eventos.

Dado el consumo eléctrico de una vivienda (voltage y corriente) queremos detectar en que momento se produce una conexión de un dispositivo. Para ello, filtraremos la señal sinusoidal obteniendo el valor eficaz de la corriente cada cierto intervalo. Los cambios en el valor eficaz van a determinar las conexiones y desconexiones de los distintos dispositivos. Derivando este valor eficaz, obtenemos picos en los que existe un cambio en el valor eficaz y, por lo tanto, posibles candidatos a eventos de conexión/desconexión. Finalmente, usando un detector de picos filtraremos los eventos reales del resto.

Mediremos nuestros resultados usando métricas estándar de NILM.

Paso por paso

Importar pandas, numpy y matplotlib tal y como se ha visto anteriormente

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt

Definir una funcion llamada rms_function que devuelva un valor rms y que tenga como parámetro de entrada un vector de valores

# función rms 
def rms_function(x): 
    return np.sqrt(np.mean(np.square(x)))

Usar el siguiente path para cargar los datos en un dataframe df de pandas. Como parámetros: el índice es la columna 0 (index_col) y la fecha está en la columna 1 (parse_dates)

path='data/smart_meter_data.csv'
df= ...
path='data/smart_meter_data.csv'
df=pd.read_csv(path, parse_dates=[1],index_col=[0])

Mostrar las 5 primeras columnas del dataframe

df.head(5)
datetimeivlabelappl_namephase
02011-10-20 12:21:58.9730000.444955159.194375111RefrigeratorA
12011-10-20 12:21:58.9730830.402501160.677554111RefrigeratorA
22011-10-20 12:21:58.9731660.444955161.845163111RefrigeratorA
32011-10-20 12:21:58.9732491.102993163.107443111RefrigeratorA
42011-10-20 12:21:58.9733321.952074164.243495111RefrigeratorA

Imprimir mínimo y máximo de datetime y la diferencia de ambos

print (df.datetime.min())
print (df.datetime.max())
print (df.datetime.max()-df.datetime.min())
2011-10-20 12:21:58.973000
2011-10-20 12:23:03.713996
0 days 00:01:04.740996

Seleccionar datetime como índice del dataframe df

df.index=df.datetime

Periodo y frequencia de muestreo

# frecuencia
ts=df.datetime.diff().mean().total_seconds()
print (str(ts)+' seconds')
fs=1/ts
print ( str(fs)+' Hz')
8.3e-05 seconds
12048.192771084337 Hz

Dibujar Voltage (v) haciendo zoom en el intervalo de 100ms (6 periodos aproximadamente)

d1='2011-10-20 12:22:29.9'
d2='2011-10-20 12:22:30'
df[(df.index>d1)&(df.index<d2)].v.plot()
<matplotlib.axes._subplots.AxesSubplot at 0x7f6e2b9f86d8>
df.i.plot()
<matplotlib.axes._subplots.AxesSubplot at 0x7f6e2e274d30>

Resamplear mediante la función resample de pandas a 50ms (’50L’). La función rms_function se pasará como parámetro para obtener cada valor del resampleado. El resultado debe de guardarse en un dataframe nuevo llamado rms . Dibujar el resultado.

rms=pd.DataFrame(df.i.resample(....))
rms=pd.DataFrame(df.i.resample('50L',how=rms_function))
rms.plot()
<matplotlib.axes._subplots.AxesSubplot at 0x7f6e2f8848d0>

Hacer la derivada del dataframe rms y guardar el resultado en rms_diff.

rms_diff=rms.diff()

Dibujar el resultado (rms_diff)

rms_diff.plot()
<matplotlib.axes._subplots.AxesSubplot at 0x7f6e2f7f9fd0>

Guardar los valores de la columna «i» en una variable «y» en forma de array

y=rms_diff.i.values
Modifica los parámetros th_noise y dist de la función detect_peaks para obener los índices de los eventos y evaluar las métricas. Realizar el proceso 3 veces. ¿ Con qué valores de th_noise y dist se obtienen mejores resultados en las métricas?
th_noise=5
dist=5
from detect_peaks import detect_peaks
indexes=detect_peaks(y,mph=th_noise,mpd=dist)
dates=rms_diff.ix[indexes].index

Cuantos eventos hemos detectado

print (str(len(indexes))+' eventos detectados')
8 eventos detectados

Dibujamos los eventos y la corriente en una misma gráfica

plt.vlines(dates,-80,80)
df.i.plot()
<matplotlib.axes._subplots.AxesSubplot at 0x7f6e2f79ca58>

Métricas

from IPython.display import Image
Image(filename='metricas1.png')
Image(filename='metricas2.png')

Obtener las métricas: recall, precision y F1

FP=0.
P=9.
N=len(df)-P
TN=N-FP
P=9.
N=len(df)-P
TP=8.
FP=0.
FN=1.
TN=N-FP
recall=TP/(TP+FN)
precision=TP/(TP+FP)
F1=2*precision*recall/(precision+recall)
print (recall)
print (precision)
print (F1)
0.8888888888888888
1.0
0.9411764705882353

*Parámetros optimizados: * th_noise=0.1 y dist=5

*Con esto obtenemos : * recall=1, precision=1 y F1=1;