Анализ данных с помощью pandas. Часть 4: объединение нескольких dataframe
В конце этой части, мы загрузим данные о погоде в Канаде за весь 2012 год, и сохраним в CSV файл. Мы сделаем это, загрузив каждый месяц в отдельности, а затем сгруппировав все месяцы вместе.
Здесь температура за каждый час в 2012 году!
In [1]:%matplotlib inline
import pandas as pd
import matplotlib.pyplot as plt
import numpy as np
pd.options.display.max_rows = 7
plt.style.use('ggplot')
plt.rcParams['figure.figsize'] = (15, 3)
plt.rcParams['font.family'] = 'sans-serif'
weather_2012_final = pd.read_csv('data/weather_2012.csv', index_col='Date/Time')
weather_2012_final['Temp (C)'].plot(figsize=(18, 6))
Загрузка данных за 1 месяц
При работе с данными о велосипедистах, мы хотим только данные о температуре и осадках, чтобы понять, много ли людей любит кататься на велосипеде в дождь. Для этого зайдем на сайт исторических данных о погоде в Канаде, и посмотрим, можно ли это сделать автоматически.
Сейчас мы возьмём данные за 2012 год, и уберем из них все ненужное нам.
Это адрес с данными для Монреаля:
In [3]:url_template = "http://climate.weather.gc.ca/climate_data/bulk_data_e.html?format=csv&stationID=5415&Year={year}&Month={month}&timeframe=1&submit=Download+Data"
Чтобы получить данные за март 2012, мы должны форматировать строку с month=3, year=2012
.
url = url_template.format(month=3, year=2012)
weather_mar2012 = pd.read_csv(url, skiprows=15, index_col='Date/Time', parse_dates=True, encoding='latin1')
Это здорово! Мы можем использовать read_csv
, как и раньше, и просто использовать URL как имя файла.
В начале файла 16 строк метаданных, но pandas знает, что CSV могут быть странными, поэтому у read_csv
есть опция skiprows
. Мы снова обрабатываем даты, и устанавливаем 'Date/Time' в качестве индекса. Это получившийся dataframe.
weather_mar2012
Year | Month | Day | Time | Data Quality | Temp (°C) | Temp Flag | Dew Point Temp (°C) | Dew Point Temp Flag | Rel Hum (%) | ... | Wind Spd Flag | Visibility (km) | Visibility Flag | Stn Press (kPa) | Stn Press Flag | Hmdx | Hmdx Flag | Wind Chill | Wind Chill Flag | Weather | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Date/Time | |||||||||||||||||||||
2012-03-01 00:00:00 | 2012 | 3 | 1 | 00:00 | -5.5 | NaN | -9.7 | NaN | 72 | ... | NaN | 4.0 | NaN | 100.97 | NaN | NaN | NaN | -13.0 | NaN | Snow | |
2012-03-01 01:00:00 | 2012 | 3 | 1 | 01:00 | -5.7 | NaN | -8.7 | NaN | 79 | ... | NaN | 2.4 | NaN | 100.87 | NaN | NaN | NaN | -13.0 | NaN | Snow | |
2012-03-01 02:00:00 | 2012 | 3 | 1 | 02:00 | -5.4 | NaN | -8.3 | NaN | 80 | ... | NaN | 4.8 | NaN | 100.80 | NaN | NaN | NaN | -13.0 | NaN | Snow | |
... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
2012-03-31 21:00:00 | 2012 | 3 | 31 | 21:00 | 2.6 | NaN | -6.3 | NaN | 52 | ... | NaN | 25.0 | NaN | 100.86 | NaN | NaN | NaN | NaN | NaN | Clear | |
2012-03-31 22:00:00 | 2012 | 3 | 31 | 22:00 | 2.7 | NaN | -6.7 | NaN | 50 | ... | NaN | 25.0 | NaN | 100.82 | NaN | NaN | NaN | NaN | NaN | Clear | |
2012-03-31 23:00:00 | 2012 | 3 | 31 | 23:00 | 1.5 | NaN | -6.9 | NaN | 54 | ... | NaN | 25.0 | NaN | 100.79 | NaN | NaN | NaN | NaN | NaN | Clear |
744 rows × 24 columns
Построим график температуры!
In [6]:weather_mar2012["Temp (°C)"].plot(figsize=(15, 5))
Давайте исправим названия некоторых столбцов (согласитесь, не очень удобен столбец "Temp (°C)").
In [7]:weather_mar2012.columns = [
u'Year', u'Month', u'Day', u'Time', u'Data Quality', u'Temp (C)',
u'Temp Flag', u'Dew Point Temp (C)', u'Dew Point Temp Flag',
u'Rel Hum (%)', u'Rel Hum Flag', u'Wind Dir (10s deg)', u'Wind Dir Flag',
u'Wind Spd (km/h)', u'Wind Spd Flag', u'Visibility (km)', u'Visibility Flag',
u'Stn Press (kPa)', u'Stn Press Flag', u'Hmdx', u'Hmdx Flag', u'Wind Chill',
u'Wind Chill Flag', u'Weather']
Есть много столбцов, которые почти полностью пусты. Давайте удалим их с помощью функции dropna
.
Аргумент axis=1
у dropna
означает "удалить столбцы, а не строки", и how='any'
означает "удалить столбец, если хотя бы одно значение пусто".
Сейчас гораздо лучше - у нас только столбцы с реальными данными.
In [8]:weather_mar2012 = weather_mar2012.dropna(axis=1, how='any')
weather_mar2012[:5]
Year | Month | Day | Time | Data Quality | Temp (C) | Dew Point Temp (C) | Rel Hum (%) | Wind Spd (km/h) | Visibility (km) | Stn Press (kPa) | Weather | |
---|---|---|---|---|---|---|---|---|---|---|---|---|
Date/Time | ||||||||||||
2012-03-01 00:00:00 | 2012 | 3 | 1 | 00:00 | -5.5 | -9.7 | 72 | 24 | 4.0 | 100.97 | Snow | |
2012-03-01 01:00:00 | 2012 | 3 | 1 | 01:00 | -5.7 | -8.7 | 79 | 26 | 2.4 | 100.87 | Snow | |
2012-03-01 02:00:00 | 2012 | 3 | 1 | 02:00 | -5.4 | -8.3 | 80 | 28 | 4.8 | 100.80 | Snow | |
2012-03-01 03:00:00 | 2012 | 3 | 1 | 03:00 | -4.7 | -7.7 | 79 | 28 | 4.0 | 100.69 | Snow | |
2012-03-01 04:00:00 | 2012 | 3 | 1 | 04:00 | -5.4 | -7.8 | 83 | 35 | 1.6 | 100.62 | Snow |
Столбцы Year/Month/Day/Time лишние, кроме того, столбец "Data Quality" тоже не слишком полезен. Удалим их.
axis=1
означает "удалить столбцы", как и раньше. По умолчанию dropna
и drop
всегда удаляют строки (axis=0
).
weather_mar2012 = weather_mar2012.drop(['Year', 'Month', 'Day', 'Time', 'Data Quality'], axis=1)
weather_mar2012[:5]
Temp (C) | Dew Point Temp (C) | Rel Hum (%) | Wind Spd (km/h) | Visibility (km) | Stn Press (kPa) | Weather | |
---|---|---|---|---|---|---|---|
Date/Time | |||||||
2012-03-01 00:00:00 | -5.5 | -9.7 | 72 | 24 | 4.0 | 100.97 | Snow |
2012-03-01 01:00:00 | -5.7 | -8.7 | 79 | 26 | 2.4 | 100.87 | Snow |
2012-03-01 02:00:00 | -5.4 | -8.3 | 80 | 28 | 4.8 | 100.80 | Snow |
2012-03-01 03:00:00 | -4.7 | -7.7 | 79 | 28 | 4.0 | 100.69 | Snow |
2012-03-01 04:00:00 | -5.4 | -7.8 | 83 | 35 | 1.6 | 100.62 | Snow |
Здорово! Теперь проще работать с этими данными.
Дневной график температуры
Просто так - мы этим уже занимались в предыдущей части. Но давайте сделаем это. Графики красивы.
In [10]:temperatures = weather_mar2012[[u'Temp (C)']].copy()
temperatures.loc[:,'Hour'] = weather_mar2012.index.hour
temperatures.groupby('Hour').aggregate(np.median).plot()
Наибольшая температура (по медиане) приходится на 2 часа дня. Неплохо.
Получаем данные за год
Как теперь получить данные за весь год? В идеале, сайт должен предоставлять такую возможность, но на практике такой возможности нет.
Во-первых, у нас есть функция, получающая данные за месяц:
In [11]:def download_weather_month(year, month):
url = url_template.format(year=year, month=month)
weather_data = pd.read_csv(url, skiprows=15, index_col='Date/Time', parse_dates=True)
weather_data = weather_data.dropna(axis=1)
weather_data.columns = [col.replace('\xb0', '') for col in weather_data.columns]
weather_data = weather_data.drop(['Year', 'Day', 'Month', 'Time', 'Data Quality'], axis=1)
return weather_data
Проверим, что функция работает верно:
In [12]:download_weather_month(2012, 1)[:5]
Temp (C) | Dew Point Temp (C) | Rel Hum (%) | Wind Spd (km/h) | Visibility (km) | Stn Press (kPa) | Weather | |
---|---|---|---|---|---|---|---|
Date/Time | |||||||
2012-01-01 00:00:00 | -1.8 | -3.9 | 86 | 4 | 8.0 | 101.24 | Fog |
2012-01-01 01:00:00 | -1.8 | -3.7 | 87 | 4 | 8.0 | 101.24 | Fog |
2012-01-01 02:00:00 | -1.8 | -3.4 | 89 | 7 | 4.0 | 101.26 | Freezing Drizzle,Fog |
2012-01-01 03:00:00 | -1.5 | -3.2 | 88 | 6 | 4.0 | 101.27 | Freezing Drizzle,Fog |
2012-01-01 04:00:00 | -1.5 | -3.3 | 88 | 7 | 4.8 | 101.23 | Fog |
Теперь объединим все месяцы. Получим их:
In [13]:data_by_month = [download_weather_month(2012, i) for i in range(1, 13)]
Объединим dataframe с помощью pd.concat
. Теперь у нас данные за весь год!
weather_2012 = pd.concat(data_by_month)
weather_2012
Temp (C) | Dew Point Temp (C) | Rel Hum (%) | Wind Spd (km/h) | Visibility (km) | Stn Press (kPa) | Weather | |
---|---|---|---|---|---|---|---|
Date/Time | |||||||
2012-01-01 00:00:00 | -1.8 | -3.9 | 86 | 4 | 8.0 | 101.24 | Fog |
2012-01-01 01:00:00 | -1.8 | -3.7 | 87 | 4 | 8.0 | 101.24 | Fog |
2012-01-01 02:00:00 | -1.8 | -3.4 | 89 | 7 | 4.0 | 101.26 | Freezing Drizzle,Fog |
... | ... | ... | ... | ... | ... | ... | ... |
2012-12-31 21:00:00 | -0.5 | -1.5 | 93 | 28 | 4.8 | 99.95 | Snow |
2012-12-31 22:00:00 | -0.2 | -1.8 | 89 | 28 | 9.7 | 99.91 | Snow |
2012-12-31 23:00:00 | 0.0 | -2.1 | 86 | 30 | 11.3 | 99.89 | Snow |
8784 rows × 7 columns
Сохранить dataframe в CSV файл
Вы заметили, что функция download_weather_month
выполняется медленно? Не стоит каждый раз загружать эти данные, поэтому сохраним результат в CSV файл.
weather_2012.to_csv('data/weather_2012.csv')