Как предсказывать загрязнение воздуха с помощью нейросетей

Задача нейросети будет в предсказании значения концентрации PM10 вредных частиц, содержащихся в воздухе, основываясь на других измерениях приборов.

Кратко о данных. Специальное оборудование производило замеры содержания в воздухе различных газов и взвешенных частиц, температуры воздуха, скорости ветра, атмосферного давления, даты и времени. Измерения производились каждые 20 минут в течении полутора лет. Следовательно, датасет содержит около 34 тыс. строк.

После осмотра файлов выяснилось, что в данных присутствуют сбойные измерения, от этих строк необходимо избавиться.

Подгружаю датасет: так как данные разбиты по разным .csv файлам, то воспользуюсь функцией concat.

import pandas as pd data_dir = Path("/content/drive/MyDrive/Data/") df = pd.concat([pd.read_csv(filepath_or_buffer=f, sep=';', encoding='cp1251', decimal=',') for f in data_dir.glob("*.csv")], ignore_index=True)

Исключаю ошибочные замеры, а также преобразую данные к нужному формату.

incorrect = ['нет связи', 'Ошибка', 'Откл.', 'нет в БД', ' ---', 'Кaлибр.', 'Отказ', 'no', 'Нестаб', '--'] def replace_incorrect(x): x = str(x) if x in incorrect or x == '': return np.nan else: x = float(str(x).replace(',', '.')) return x for column in df.columns: if column == 'Время': continue df[column] = df[column].apply(replace_incorrect) df = df.dropna()

Вывожу данные для первичной оценки:

Отсюда видно, что величина данных сильно разнится, такие данные требуют дополнительной обработки, а именно нормализации и исключения выбросов.

Чтобы избавиться от выбросов использую гистограммы BoxPlot, я исключаю все данные, которые лежат выше верхней и ниже нижней границы.

for column in df.columns: #вычисление квантилей Q1 = df[column].quantile(q=0.25) Q3 = df[column].quantile(q=0.75) #межквантильное расстояние IQR = Q3 - Q1 df.loc[df[column] < Q1-1.5*IQR, column] = np.nan df.loc[df[column] > Q3+1.5*IQR, column] = np.nan df = df.dropna()

Для нормализации в нейросеть будет добавлен слой BatchNormalization.

Чтобы удалённые строки не так критично влияли на результаты, усредняю данные по дням.

df_day = df.copy() df_day = df_day.set_index('Время').groupby(pd.Grouper(freq='d')).mean().dropna(how='all')

Разбиваю датасет на обучающую и тестовую выборки.

from sklearn.model_selection import train_test_split var = np.matrix(df_day.drop(['PM10, мг/м3'], axis=1)) ans = np.array(df_day['PM10, мг/м3']) train_var, test_var, train_ans, test_ans = train_test_split(var, ans, shuffle=False, test_size=0.2)

В качестве функций активации были выбраны ReLU, ELU, так как они, как правило, лучше себя показывают в задачах регрессии. На выходе из нейронной сети находится линейная функция. Всего в сети 8 слоёв, содержащих в себе в сумме 21000 параметров, в качестве оптимизатора выбран стохастический градиентный спуск.

Также для избавления от переобучения в один из слоёв включена l2 регуляризация.

from keras.Dense.layers import Input, Dense, BatchNormalization regression model = Sequential() regression_model.add(Input(shape=train_var.shape[1])) #слой нормализации regression_model.add(BatchNormalization()) regression_model.add(Dense(64)) regression_model.add(Dense(64, activation='relu')) regression_model.add(Dense(64, activation=ELU)) regression_model.add(Dense(64, kernel_regularizer=keras.regularizers.l2(0.01), activation='relu')) regression_model.add(Dense(64, activation='ELU')) regression_model.add(Dense(64, activation='relu')) regression_model.add(Dense(1, activation='linear')) regression_model.compile(optimizer='sgd', loss='mse') regression_model.summary()

Запускаю обучение, на практике получил, что модель выходит на асимптоту ошибки примерно за 150 эпох.

regression_model.fit(train_var, train_ans, validation_split=0.3, epochs=150) CPU times: user 9.95 s, sys: 697 ms, total: 10.6 s Wall time: 9.23 s

Ну, а теперь можно оценить, как нейронка покажет себя на тестовой выборке.

from matplotlib import pyplot as plt ans_predict = regression_model.predict(test_var) plt.figure(figsize=(14, 14)) plt.plot(test_ans, label='Известные данные') plt.plot(ans_predict, color='red', label='Предсказанные') plt.legend(['Известные данные', 'Предсказанные']) plt.show()

Среднеквадратичная и абсолютная ошибки.

mse = ((test_ans - ans_predict)**2).sum()/len(y_test) mae = (abs(test_ans - ans_predict)).sum()/len(y_test) print('mse: ', mse, '\nmae: ', mae) mse: 0.000539640676060587 mae: 0.018231081658013435

На графике видно, что модель уловила некоторые пики выбросов. По MSE и MAE также можно сказать, что результаты неплохие, однако из-за удаления некоторых строк из датасета предсказанные значения все же не идеальные. Отсюда можно сделать вывод, что нейросети могут быть применимы в задачах, связанных с регрессией и выдавать приемлемый результат.

Благодарю за прочтение! Если пост показался вам полезным, можете поставить лайк, а также написать в комментариях, как можно улучшить полученные результаты.

0
2 комментария
Sergey Ilyin

Спасибо вам за статьи с кодом! Ибо тут это крайне редко, а на Хабре может потеряться среди других.

Ответить
Развернуть ветку
NTA
Автор

Благодарим за проявленный интерес!

Ответить
Развернуть ветку
-1 комментариев
Раскрывать всегда