Importar CSV a Python y convertir columnas separadas a formato datetime para graficar

publicado por: Anonymous

Cómo hago para importar un archivo de ese estilo (csv) y graficar datetime vs la columna DECL ? y otra cosa, cómo podría hacer para graficar por ej. solamente todos los meses de un año especifico y omitir todas las fechas con valor de CERO?. gracias

Link de todo el set de datos: https://www.datos.gov.co/widgets/myx5-mu3h

introducir la descripción de la imagen aquí

solución

Este es el tipo de tareas para el cual pandas ha sido creado. Te invito a que leas la documentación o los muchos tutoriales y ejemplos que hay sobre él en internet, o te compres un buen libro. Si vas a tener que tratar con este tipo de problemas a menudo, te acabará compensando.

Como pandas es un mundo, y asumo que no lo conoces, no puedo pararme a explicar la sintaxis o el por qué de cada uno de los pasos. Confío en que sean hasta cierto punto autoexplicativos y que te piquen la curiosidad por aprender más sobre este excelente paquete.

1. Leer los datos

import pandas as pd
url = "http://datos.igac.gov.co/datasets/c2b2cbf67faa49b5951bd78499a1d8a8_0.csv"
df = pd.read_csv(url)

Podemos ver si lo ha leido bien, volcando el inicio de la tabla con print(df.head()):

   OBJECTID   ANO  MES  DIA  HORA     DECL  HORIZONTAL   VERTICAL  
0      3001  1955    5    6     1  1.16833   30456.792  20415.666   
1      3002  1955    5    6     2  1.17167   30441.474  20421.854   
2      3003  1955    5    6     3  1.18333   30444.786  20424.402   
3      3004  1955    5    6     4  1.18333   30454.722  20423.310   
4      3005  1955    5    6     5  1.18500   30450.582  20420.034   

         NORTE       ESTE    INT_TOTAL      INCL  
0  30450.46020  621.00943  36666.27329  33.83457  
1  30435.10922  622.46774  36656.99742  33.85593  
2  30438.29313  628.73338  36661.16735  33.85636  
3  30448.22702  628.93857  36668.81077  33.84629  
4  30444.06959  629.73866  36663.54774  33.84564 

Parece correcto, pero las columnas que contienen los datos de la fecha deberían llamarse “year”, “month”, “day” y “hour” para que Pandas las pueda reconocer y convertir automáticamente. Renombrémoslas:

nombres = {"ANO": "year", "MES": "month", "DIA": "day", "HORA": "hour"}
df = df.rename(columns=nombres)

2. Quedarse con lo que necesitamos

Necesitamos agregar un índice al dataframe que, en lugar de ser un entero creciente, sea la fecha (datetime) de cada fila.

df.index = pd.to_datetime(df[["year", "month", "day", "hour"]])

Ahora nos quedaremos solo con la columna que nos interesa:

df = df[["DECL"]]

Podemos ver con print(df.head()) qué pinta tiene el dataframe:

                        DECL
1955-05-06 01:00:00  1.16833
1955-05-06 02:00:00  1.17167
1955-05-06 03:00:00  1.18333
1955-05-06 04:00:00  1.18333
1955-05-06 05:00:00  1.18500

3. Eliminar las filas con valores nulos y con ceros

print(len(df))

df = df.dropna()
df = df[df.DECL != 0]

print(len(df))

Vemos que antes de la limpieza tenía 525960 datos y después tiene 507222. Hemos eliminado cerca de 20000 datos nulos.

4. Graficar lo que queda:

df.plot()

Plot

5. Graficar sólo una parte

Por ejemplo, 1960

df["1960-01":"1960-12"].plot()

1960

O el mes de agostro de 2010:

df["2010-08"].plot()

Agosto 2010

Más cosas…

No sé si es esto lo que preguntabas, pero ya que los datos vienen con una resolución de horas, quizás quieras agregarlos de alguna forma, por ejemplo calcular el promedio cada mes:

media_mensual = df.resample("m").mean()
print(media_mensual.head())

Pintar esta media para el año 2000:

media_mensual["2000"].plot()

media mensual del 2000

Regresión

Respondiendo a otra pregunta en los comentarios. Para hacer una regresión lineal podemos usar numpy.polyfit(). Veamos como ejemplo cómo hacerlo sobre los datos de la última gráfica.

En primer lugar, ya que polyfit() requiere una serie de valores para las variables x e y sobre los que calcular la regresión, debemos pensar qué usar para esos valores. Está claro que la y serán los datos del dataframe, extrayendo los que correspondan a las fechas de interés. Por ejemplo:

y = media_mensual["2000"].DECL.values

En cuanto a las x tenemos un problema, ya que en el dataframe el índice es de tipo datetime, pero necesitamos una variable real o entera. Tendríamos que convertir cada fecha/hora a un timestamp, una marca de tiempo de tipo entero. Lo siguiente convierte cada fecha a una marca de tiempos igual al número de milisegundos transcurridos desde 1970 hasta esa fecha (puede tomar valores negativos):

x = media_mensual["2000"].index.astype(int)

Una vez tenemos los vectores x e y, la regresión lineal se hace con:

coefs = np.polyfit(x, y, 1)

Siendo el resultado -3.82425532e-18, -1.76997616e+00. El primero es la pendiente y el segundo la ordenada en el origen.

Podemos pintar esta recta frente a la curva original:

import matplotlib.pyplot as plt
plt.plot(x, y , label="original")
plt.plot(x, x*coefs[0] + coefs[1], label="regresión")
plt.legend()

Regresión

Respondido por: Anonymous

Leave a Reply

Your email address will not be published. Required fields are marked *