Tengo un DataFrame con algunos datos ( más sensuales ) en la siguiente forma:

In[67] df
Out[67]: 
                             latency
timestamp                           
2016-09-15 00:00:00.000000  0.042731
2016-09-15 00:16:24.376901  0.930874
2016-09-15 00:33:19.268295  0.425996
2016-09-15 00:51:30.956065  0.570245
2016-09-15 01:09:23.905364  0.044203
                             ...
2017-01-13 13:08:31.707328  0.071137
2017-01-13 13:25:41.154199  0.322872
2017-01-13 13:38:19.732391  0.193918
2017-01-13 13:57:36.687049  0.999191

Por lo tanto, se extiende alrededor de 50 días, y las marcas de tiempo son no a la misma hora todos los días. Me gustaría superponer algunas parcelas para cada día, es decir, inspeccionar las series de tiempo de cada día en la misma parcela. 50 días pueden ser demasiadas líneas, pero creo que hay una especie de "estacionalidad diaria" que me gustaría investigar, y esto parece una visualización útil antes de algo más riguroso.

¿Cómo superpongo estos datos en el mismo gráfico que representa un período de "día único" ?


Mis pensamientos

Todavía no estoy muy familiarizado con Pandas, pero logré agrupar mis datos en contenedores diarios con

In[67]: df.groupby(pd.TimeGrouper('D'))
Out[68]: <pandas.core.groupby.DataFrameGroupBy object at 0x000000B698CD34E0>

Ahora he estado tratando de determinar cómo se supone que debo crear una nueva estructura de DataFrame para que los diagramas puedan superponerse. Esto es lo fundamental que no puedo entender: ¿cómo puedo utilizar un objeto DataFrameGroupBy para superponer las parcelas? Un enfoque aparentemente muy rudimentario sería simplemente iterar sobre cada objeto GroupBy, pero mi problema al hacerlo ha sido configurar el eje x de modo que solo muestre un "período de tiempo diario" independiente del día en particular, en lugar de capturar el marca de tiempo completa.

Dividiendo los datos en marcos separados y llamándolos en la misma figura con algún tipo de coerción de fecha para usar el enfoque en esta respuesta más general no me parece muy bueno.


Puede generar pseudodatos de manera similar con algo como esto:

import datetime 

start_date = datetime.datetime(2016, 9, 15)
end_date = datetime.datetime.now()

dts = []
cur_date = start_date
while cur_date < end_date:
    dts.append((cur_date, np.random.rand()))
    cur_date = cur_date + datetime.timedelta(minutes=np.random.uniform(10, 20))
7
Eric Hansen 13 ene. 2017 a las 23:17

4 respuestas

La mejor respuesta

Considere el marco de datos df (generado principalmente a partir del código proporcionado por OP)

import datetime 

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

start_date = datetime.datetime(2016, 9, 15)
end_date = datetime.datetime.now()

dts = []
cur_date = start_date
while cur_date < end_date:
    dts.append((cur_date, np.random.rand()))
    cur_date = cur_date + datetime.timedelta(minutes=np.random.uniform(10, 20))


df = pd.DataFrame(dts, columns=['Date', 'Value']).set_index('Date')

El verdadero truco es dividir el índice en componentes de fecha y hora y desapilar. Luego interpolar para completar los valores faltantes

d1 = df.copy()
d1.index = [d1.index.time, d1.index.date]
d1 = d1.Value.unstack().interpolate()

Desde aquí podemos d1.plot(legend=0)

ax = d1.plot(legend=0)
ax.figure.autofmt_xdate()

enter image description here

Pero eso no es muy útil.


Puede intentar algo como esto ... espero que esto ayude

n, m = len(d1.columns) // 7 // 4 + 1, 4
fig, axes = plt.subplots(n, m, figsize=(10, 15), sharex=False)

for i, (w, g) in enumerate(d1.T.groupby(pd.TimeGrouper('W'))):
    r, c = i // m, i % m
    ax = g.T.plot(ax=axes[r, c], title=w, legend=0)

fig.autofmt_xdate()

enter image description here


Cómo hacerlo durante semanas

  • crear un índice múltiple
    • incluye el período que representa la semana
    • incluye el día de la semana
    • incluye la hora del día
  • unstack para obtener períodos semanales en columnas
  • Todavía no está convencida del formato del eje.

d2 = df.copy()

idx = df.index
d2.index = [idx.weekday_name, idx.time, idx.to_period('W').rename('Week')]

ax = d2.Value.unstack().interpolate().iloc[:, :2].plot()
ax.figure.autofmt_xdate()

enter image description here

7
Victor Uriarte 14 mar. 2019 a las 17:17

Recientemente tuve que hacer un diagrama muy similar usando eventos aleatorios con fecha y hora para los datos que estaba analizando.

Necesita agregar otra columna en su marco de datos para encontrar el tiempo transcurrido

Asegúrese de que sus datos de marca de tiempo sean un objeto de fecha y hora de Python primero, luego haga

df['Elapsed_Time'] = df['timestamp'] - df['timestamp'][0]
df['Elapsed_Time'] = df['Elapsed_Time'] / datetime.timedelta(days=1)

Ahora debería tener un marco de datos con una columna de tiempo transcurrido (algo como lo siguiente. Estoy usando mi propio conjunto de datos para mostrarle lo que quiero decir)

enter image description here

Además, si desea una trama cada hora en lugar de todos los días. Luego, solo use horas en lugar de días en la línea

df['Elapsed_Time'] = df['Elapsed_Time'] / datetime.timedelta(hours=1)

Próximos pasos: trazar

La idea es repasar el conjunto de datos fila por fila y agregar datos que caen en un día y luego agregarlos a una lista

latency = []
next_day = 1
inds = []
for (i, t) in enumerate(list(df['Elapsed_Time'])):
    if t < next_day:
        inds.append(i)
    else:
        latency.append(df.iloc[inds]))
        next_day += 1
        inds = []
plt.plot(latency, "bo--", label="latencyperday")

Este es el resultado final (usando mi propio conjunto de datos para mostrarle cómo se vería). Espero que esto ayude

enter image description here

0
Imran 14 ene. 2017 a las 03:29

Si agrega columnas de columna separadas para la fecha y la hora, solo tiene que trazar el tiempo en función de la latencia para cada fecha.

df = df.assign(date=df.index.date, time=df.index.time)
for date in df.date.unique():
    plt.plot('time', 'latency', data=df[df.date == date])
    plt.xlabel('latency')
0
Stop harming Monica 13 ene. 2017 a las 21:26

No ha mencionado qué operación tiene previsto en las latencias agrupadas por día. Digamos que si toma valores medios, puede trazar un gráfico lineal simple como este:

df = pd.DataFrame(dts)
df.columns = ['Timestamp', 'Latency']

df.groupby(pd.TimeGrouper(key='Timestamp',freq='D')).mean().plot()
0
Vaishali 13 ene. 2017 a las 20:58