Los datos registrados para un punto, tabulados en el proceso anterior requieren un análisis básico para obtener descriptores estadísticos que los representen. A partir del archivo ejemplo mostrado, se pueden obtener los siguientes resultados:
Por ejemplo, para analizar el nivel de señal (rssi_up, rssi_down) se requiere de los parámetos de media, desviación estándar, medias móviles, función de probabilidad de masa (pmf), etc. Los parámetros se pueden resumir en tablas y gráficas semejantes a la mostrada.
descriptor estadístico para los datos de la gráfica
descriptor rssi_up rssi_down count 98.000000 98.00000 mean -86.336735 -77.44898 std 3.782608 1.14083 min -97.000000 -81.00000 25% -89.000000 -78.00000 50% -86.000000 -77.00000 75% -84.000000 -77.00000 max -78.000000 -75.00000 error_trama 0.000000 0.00000
Para el proceso se requiere el nombre del punto, la carpeta o directorio donde se encuentra, la medida a observar (ej: rssi).
Un parámetro como la media puede se insuficiente para observar el comportamiento, por lo que se añaden las medias móviles.
Para la media móvil se debe indicar cada cuántas muestras se obtendrá el promedio, por lo que al usar varias se darán varias de ellas mediante la variable movAvg_cual.
Errores en una trama
Se consideran errores de medida a los valores fuera de un intervalo expresado en «medida_normal». Al indicar si un dato tiene un error es posible determinar la tasa de error en de trama, para el canal de subida y de bajada.
Registros a procesar
Los registros que se procesarán serán libres de errores de trama, donde se calculan la media, desviación estándar, mínimo, máximo. Los resultados son los mostrados en la tabla.
Funciones de Probabilidad de masa (pmf)
Para cada valor de medida (rssi), se obtiene la frecuencia relativa que se presentan en una gráfica pmf.
Archivos de resultado
Los resultados se guardan en archivos.csv y graficos.pmf para el registro del análisis de cada punto. Loa archivos se agrupan en una carpeta de resultados para su posterior análisis en conjunto.
Instrucciones en Python
# Descriptores estadisticos de los datos.csv # de un dispositivo, revisa media, desviació estándar, pmf # graba unreporte.csv con pandas y genera gráficas # http://blog.espol.edu.ec/girni/ import numpy as np import json import pandas as pd import datetime as dt import os import matplotlib.pyplot as plt import matplotlib.dates as mdates import matplotlib.units as munits # INGRESO cualpunto = "data_m_LOS22.csv" carpeta_rsm = "resultado_Test" medida = "rssi" medida_unidad = "dBm" medida_normal = [-250,-1] medida_grafica = [-100,-60] movAvg_cual = [8,16] #cada cuantas muestras movAvg_color = ['lightgreen','orange'] precision = 2 guarda = True # PROCEDIMIENTO unmodelo = cualpunto.strip('.csv').split('_')[1] unubicado = cualpunto.strip('.csv').split('_')[2] codigopunto = unmodelo+'_'+unubicado # Leer archivo archivopunto = carpeta_rsm + '/' + cualpunto tabla = pd.read_csv(archivopunto) tabla = tabla.drop(columns='Unnamed: 0') tabla = pd.DataFrame(tabla) fechaformato = "%Y-%m-%d %H:%M:%S.%f" # medida intervalo medida_min = np.min(medida_normal) medida_max = np.max(medida_normal) # fechas series a datetime tabla['publishedAt'] = pd.to_datetime(tabla['publishedAt'], format=fechaformato) tabla['created'] = pd.to_datetime(tabla['publishedAt'], format=fechaformato) # revisa errores de medida tabla["error_up"] = 0 tabla["error_down"] = 0 for undato in tabla['publishedAt'].keys(): medida_up = tabla[medida+'_up'][undato] enrango = (medida_up>=np.min(medida_normal)) enrango = (enrango and medida_up<=np.max(medida_normal)) if not(enrango): tabla.at[undato,"error_up"] = 1 medida_down = tabla[medida+'_down'][undato] enrango = (medida_down>=np.min(medida_normal)) enrango = (enrango and medida_down<=np.max(medida_normal)) if not(enrango): tabla.at[undato,"error_down"] = 1 # tasa error trama leidos = len(tabla) if leidos > 0: error_up = np.sum(tabla['error_up']) error_up = error_up/leidos error_down = np.sum(tabla['error_down']) error_down = error_down/leidos # descriptor estadístico, datos sin errores condicion_up = (tabla['error_up']==0) condicion_down = (tabla['error_down']==0) medida_up = tabla[condicion_up][medida+'_up'] describe_up = medida_up.describe() describe_up['error_trama'] = error_up medida_down = tabla[condicion_down][medida+'_down'] describe_down = medida_down.describe() describe_down['error_trama'] = error_down descriptor = describe_up.copy() descriptor = pd.concat([descriptor,describe_down],axis=1) descriptor['dispositivo'] = tabla['dispositivo'][0] # función de probabilidad de masa pmf def medida_pmf(valores,undescriptor): pmin = np.min(valores) pmax = np.max(valores) tramo = int(pmax-pmin) conteo = np.zeros(tramo+1,dtype=int) intervalo = np.arange(pmin,pmax+1,1) for valor in valores: donde = np.where(intervalo == valor) conteo[donde] = conteo[donde] + 1 freq_relativa = np.array(conteo)/np.sum(conteo) unpmf = {'intervalo' : list(intervalo), 'freq_relativa' : list(freq_relativa)} return(unpmf) pmf_up = medida_pmf(medida_up,describe_up) pmf_down = medida_pmf(medida_down,describe_down) pmf_punto = {'pmf':{'pmf_up' : pmf_up, 'pmf_down' : pmf_down}} pmf_punto = pd.DataFrame(pmf_punto) pmf_punto['dispositivo'] = tabla['dispositivo'][0] # Para gráficas # medias moviles en movAvg_cual[] serie_up = pd.Series(medida_up) movAvg_up_mean = [] movAvg_up_std = [] m = len(movAvg_cual) for j in range(0,m,1): k = movAvg_cual[j] movAvg_up_mean.append(list(serie_up.rolling(k).mean())) movAvg_up_std.append(list(serie_up.rolling(k).std())) serie_down = pd.Series(medida_down) movAvg_down_mean = [] movAvg_down_std = [] for j in range(0,m,1): k = movAvg_cual[j] movAvg_down_mean.append(list(serie_down.rolling(k).mean())) movAvg_down_std.append(list(serie_down.rolling(k).std())) movAvgData ={'movAvg_cual' : movAvg_cual, 'movAvg_color' : movAvg_color, 'movAvg_up_mean' : movAvg_up_mean, 'movAvg_down_mean': movAvg_down_mean, 'movAvg_up_std' : movAvg_up_std, 'movAvg_down_std' : movAvg_down_std } grafData ={'codigopunto' : codigopunto, 'medida' : medida, 'precision': precision, 'medida_unidad' : medida_unidad, 'medida_grafica': medida_grafica } # SALIDA -------------------------- print('descriptor') print(descriptor) # guarda el reporte en csv unarchivo = carpeta_rsm+'/describe_'+codigopunto+'.csv' descriptor.to_csv(unarchivo) unarchivo = carpeta_rsm+'/pmf_'+codigopunto+'.json' pmf_punto.to_json(unarchivo) unarchivo = carpeta_rsm+'/movavg_'+codigopunto+'.json' with open(unarchivo, "w") as outfile: json.dump(movAvgData, outfile) unarchivo = carpeta_rsm+'/grfdata_'+codigopunto+'.json' with open(unarchivo, "w") as outfile: json.dump(grafData, outfile) # GRAFICA ----- def graf_puntos_serie(tabla,descriptor,movAvgData,grafData): ''' grafica la serie de tiempo de cada punto añade medias móviles ''' # ajuste de formato de fecha para eje x converter = mdates.ConciseDateConverter() munits.registry[np.datetime64] = converter munits.registry[dt.date] = converter munits.registry[dt.datetime] = converter # datos para grafica precision = grafData['precision'] medida = grafData['medida'] medida_unidad = grafData['medida_unidad'] medida_grafica = grafData['medida_grafica'] movAvg_cual = movAvgData['movAvg_cual'] movAvg_color = movAvgData['movAvg_color'] media_up = descriptor[medida+'_up']['mean'] std_up = descriptor[medida+'_up']['std'] media_down = descriptor[medida+'_down']['mean'] std_down = descriptor[medida+'_down']['std'] # ajuste de intervalo eje y y_min = np.min([np.min(medida_grafica), media_up - 2*std_up, media_down - 2*std_down]) y_max = np.max([np.max(medida_grafica), media_up + 2*std_up, media_down + 2*std_down]) # selecciona sin error condicion_up = (tabla['error_up']==0) condicion_down = (tabla['error_down']==0) # grafica fig_serie,(graf_up,graf_down) = plt.subplots(2,1) # medida_up ----- graf_up.plot(tabla[condicion_up]['publishedAt'], tabla[condicion_up][medida+'_up'], color='blue',marker ='.', linestyle='') # medida_up, medias y std etiq_up = str(np.round(media_up,precision))+' +/- ' etiq_up = etiq_up + str(np.round(std_up,precision)) graf_up.axhline(media_up, color='blue',label=etiq_up) graf_up.axhline(media_up-std_up, color='blue',linestyle='dotted') graf_up.axhline(media_up+std_up, color='blue',linestyle='dotted') # medida_up, medias móviles m = len(movAvg_cual) for j in range(0,m,1): k = str(movAvg_cual[j]) graf_up.plot(tabla[condicion_up]['publishedAt'], movAvgData['movAvg_up_mean'][j], label='movAvg_'+k, color=movAvg_color[j]) graf_up.set_ylim(y_min,y_max) graf_up.set_ylabel(medida+'_up ('+medida_unidad+')', color='blue') graf_up.legend() graf_up.grid(True,linestyle='dotted', axis='x',which='both') # medida_down ------- graf_down.plot(tabla[condicion_down]['publishedAt'], tabla[condicion_down][medida+'_down'], color='brown',marker ='.', linestyle='') # medida_down, medias y std etiq_down = str(np.round(media_down,precision))+' +/- ' etiq_down = etiq_down + str(np.round(std_down,precision)) graf_down.axhline(media_down, color='brown',label=etiq_down) graf_down.axhline(media_down+std_down, color='brown',linestyle='dotted') graf_down.axhline(media_down-std_down, color='brown',linestyle='dotted') # medida_down, medias moviles for j in range(0,m,1): k = str(movAvg_cual[j]) graf_down.plot(tabla[condicion_down]['publishedAt'], movAvgData['movAvg_down_mean'][j], label='movAvg_'+k, color=movAvg_color[j]) graf_down.set_ylim(y_min,y_max) graf_down.set_xlabel('fecha') graf_down.set_ylabel(medida+'_down ('+medida_unidad+')', color='brown') graf_down.legend() graf_down.grid(True,linestyle='dotted', axis='x', which='both') graf_up.set_title('Serie: '+grafData['codigopunto']+' '+ medida) plt.tight_layout() return(fig_serie) def graf_puntos_pmf(pmf_punto,descriptor,grafData): ''' grafica función de probabilida de masa para cada punto, media +/- std ''' # datos para grafica x_pmfup = pmf_punto['pmf']['pmf_up']['intervalo'] y_pmfup = pmf_punto['pmf']['pmf_up']['freq_relativa'] x_pmfdown = pmf_punto['pmf']['pmf_down']['intervalo'] y_pmfdown = pmf_punto['pmf']['pmf_down']['freq_relativa'] precision = grafData['precision'] medida = grafData['medida'] medida_unidad = grafData['medida_unidad'] medida_grafica = grafData['medida_grafica'] media_up = descriptor[medida+'_up']['mean'] std_up = descriptor[medida+'_up']['std'] media_down = descriptor[medida+'_down']['mean'] std_down = descriptor[medida+'_down']['std'] prob_max = 0.40 # ajuste de intervalo eje y y_min = np.min([np.min(medida_grafica), media_up - 2*std_up, media_down - 2*std_down]) y_max = np.max([np.max(medida_grafica), media_up + 2*std_up, media_down + 2*std_down]) # grafica fig_pmf,graf_pmf = plt.subplots() etiq_up = str(np.round(media_up,precision)) +' +/- ' etiq_up = etiq_up + str(np.round(std_up,precision)) graf_pmf.plot(x_pmfup,y_pmfup, label='media_up '+etiq_up, color='blue') graf_pmf.axvline(media_up,color='blue') graf_pmf.axvline(media_up+std_up, linestyle='dotted',color='blue') graf_pmf.axvline(media_up-std_up, linestyle='dotted',color='blue') etiq_down = str(np.round(media_down,precision))+' +/- ' etiq_down = etiq_down + str(np.round(std_down,precision)) graf_pmf.plot(x_pmfdown,y_pmfdown, label='media_down '+etiq_down, color='brown') graf_pmf.axvline(media_down,color='brown') graf_pmf.axvline(media_down+std_down, linestyle='dotted',color='brown') graf_pmf.axvline(media_down-std_down, linestyle='dotted',color='brown') graf_pmf.set_title('pmf: '+grafData['codigopunto']+' '+medida) graf_pmf.set_xlim(y_min,y_max) graf_pmf.set_ylim(0,prob_max) graf_pmf.set_xlabel(medida+' ('+medida_unidad+')') graf_pmf.set_ylabel('frecuencia relativa') graf_pmf.legend() graf_pmf.grid(True,linestyle='dotted', axis='x', which='both') return(fig_pmf) def graf_puntos_std(tabla,descriptor,movAvgData,grafData): ''' grafica serie de std usando medias moviles para cada punto, media_std ''' # ajuste de formato de fecha para eje x converter = mdates.ConciseDateConverter() munits.registry[np.datetime64] = converter munits.registry[dt.date] = converter munits.registry[dt.datetime] = converter # datos para grafica precision = grafData['precision'] medida = grafData['medida'] medida_unidad = grafData['medida_unidad'] movAvg_cual = movAvgData['movAvg_cual'] movAvg_color = movAvgData['movAvg_color'] # selecciona sin error condicion_up = (tabla['error_up']==0) condicion_down = (tabla['error_down']==0) # ajuste de intervalo eje y y_min = 0 y_max = np.max([2, 2*descriptor[medida+'_up']['std'], 2*descriptor[medida+'_down']['std']]) # grafica fig_std,(graf_stdUp,graf_stdDown) = plt.subplots(2,1) # std up std_up = np.round(descriptor[medida+'_up']['std'],precision) graf_stdUp.axhline(std_up,label='std '+str(std_up), color='blue') m = len(movAvg_cual) for j in range(0,m,1): k = str(movAvg_cual[j]) graf_stdUp.plot(tabla[condicion_up]['publishedAt'], movAvgData['movAvg_up_std'][j], label='movAvg_'+k, color=movAvg_color[j]) graf_stdUp.set_ylim(y_min,y_max) graf_stdUp.set_ylabel('std_up ('+medida_unidad+')', color='blue') graf_stdUp.legend() graf_stdUp.grid(True,linestyle='dotted', axis='x', which='both') graf_stdUp.set_title('std: '+grafData['codigopunto']+' '+ medida) # std down std_down = np.round(descriptor[medida+'_down']['std'],precision) graf_stdDown.axhline(std_down,label='std '+str(std_down), color='brown') for j in range(0,m,1): k = str(movAvg_cual[j]) graf_stdDown.plot(tabla[condicion_down]['publishedAt'], movAvgData['movAvg_down_std'][j], label='movAvg_'+k,color=movAvg_color[j]) graf_stdDown.set_ylim(y_min,y_max) graf_stdDown.set_xlabel('fecha') graf_stdDown.set_ylabel('std_down ('+medida_unidad+')', color='brown') graf_stdDown.legend() graf_stdDown.grid(True,linestyle='dotted', axis='x', which='both') plt.tight_layout() return(fig_std) fig_serie = graf_puntos_serie(tabla,descriptor,movAvgData,grafData) fig_pmf = graf_puntos_pmf(pmf_punto,descriptor,grafData) fig_std = graf_puntos_std(tabla,descriptor,movAvgData,grafData) if guarda==True: unarchivo = carpeta_rsm+'/serie_'+codigopunto+'.png' fig_serie.savefig(unarchivo) unarchivo = carpeta_rsm+'/pmf_'+codigopunto+'.png' fig_pmf.savefig(unarchivo) unarchivo = carpeta_rsm+'/std_'+codigopunto+'.png' fig_std.savefig(unarchivo) plt.show()
Referencia: pmf, cdf en una señal de sonido. http://blog.espol.edu.ec/estg1003/senal-de-sonido-pmf-cdf/