Выложу небольшое исследование по влиянию факторов на количество смертельных исходов на дорогах в России:

Импортируем библиотеки

!pip install shap
import shap
import pandas as pd
from sklearn.tree import DecisionTreeRegressor
import seaborn as sns
from sklearn.preprocessing import StandardScaler
from sklearn.ensemble import RandomForestRegressor
!pip install reverse_geocoder
import reverse_geocoder as rg
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt

Выгрузим данные и сразу обработаем их

improvement_coating = pd.read_excel('/content/drive/MyDrive/Счетная палата/ДТП/Протяженность_автомобильных_дорог_общего_пользования_с_усовершенствованным_покр.xlsx')
improvement_coating = improvement_coating.rename(columns=improvement_coating.iloc[0]).drop(0, axis=0)
improvement_coating.reset_index(drop=True, inplace=True)
improvement_coating = improvement_coating.drop(0, axis=0)
improvement_coating.reset_index(drop=True, inplace=True)
improvement_coating_2021 = improvement_coating[improvement_coating.columns[-1]]
improvement_coating = pd.DataFrame(data=improvement_coating[improvement_coating.columns[0]].tolist(), columns=['region_rf']).join(improvement_coating[improvement_coating.columns[2 : -1]])
improvement_coating['2021 г.'] = improvement_coating_2021
improvement_coating
road_norm = pd.read_excel('/content/drive/MyDrive/Счетная палата/ДТП/11111150300270200001_Доля_автомобильных_дорог_общего_пользования,_отвечающих_нормативным_требованиям.xlsx')
road_norm = road_norm.rename(columns=road_norm.iloc[0]).drop(0, axis=0)
road_norm.reset_index(drop=True, inplace=True)
road_norm_2021 = road_norm[road_norm.columns[-1]]
road_norm = pd.DataFrame(data=road_norm[road_norm.columns[0]].tolist(), columns=['region_rf']).join(road_norm[road_norm.columns[2 : -1]])
road_norm['2021 г.'] = road_norm_2021
road_norm
light_road = pd.read_csv('/content/drive/MyDrive/Счетная палата/скдф/Освещение дороги.csv')
light_road_for_fit = light_road.query('out_value_of_the_road == "автомобильная дорога местного значения"').groupby('out_region')['out_length',
                                                                                                            'out_defect_prop_count',
                                                                                                            'out_ligth_prop_count', 
                                                                                                            'out_light_count'].sum().reset_index()\
.rename(columns={'out_region' : 'region_rf'})

light_road_for_fit

Датасет с данными о ДТП, сразу посчитаем количество ДТП по регионам:

df = pd.read_csv('/content/drive/MyDrive/Счетная палата/ДТП/joined.csv')
df['datetime'] = pd.DatetimeIndex(df['datetime']).year
df = df[df['datetime'] == 2021]
df_group = df.groupby('parent_region')['dead_count'].sum()\
.to_frame()\
.reset_index()\
.rename(columns={'parent_region' : 'region_rf'})
df_group

Далее имеем такой датасет с установленными камерами на территории РФ

milestones = pd.read_csv('/content/drive/MyDrive/Счетная палата/ДТП/milestones.csv', sep=';')
milestones

Нам необходимо вывести регион из координат и посчитать количество установленных камер по регионам

# Функция для определения региона по батчам
def get_regions_batch(batch):
    coordinates = list(zip(batch['gps_y'], batch['gps_x']))
    results = rg.search(coordinates)
    regions = [result['admin1'] for result in results]
    return regions

# Разбиваем таблицу на батчи
batches = np.array_split(milestones, 10)

# Обрабатываем каждый батч отдельно
batch_results = []
for batch in batches:
    batch_results.append(get_regions_batch(batch))

# Объединяем результаты
results = [region for batch_result in batch_results for region in batch_result]
milestones['region'] = results

# Выводим результат
milestones

def translate_region(region):
    regions_dict = {
        'Adygeya': 'Республика Адыгея',
        'Altai Krai': 'Алтайский край',
        'Altay': 'Республика Алтай',
        'Amur': 'Амурская область',
        'Arkhangelskaya': 'Архангельская область',
        'Astrakhan': 'Астраханская область',
        'Bashkortostan': 'Республика Башкортостан',
        'Belgorod': 'Белгородская область',
        'Brjansk': 'Брянская область',
        'Chechnya': 'Чеченская Республика',
        'Chelyabinsk': 'Челябинская область',
        'Chuvashia': 'Чувашская Республика',
        'Crimea': 'Республика Крым',
        'Dagestan': 'Республика Дагестан',
        'Heilongjiang Sheng': 'Хэйлунцзян',
        'Hokkaido': 'Хоккайдо',
        'Ingushetiya': 'Республика Ингушетия',
        'Irkutsk': 'Иркутская область',
        'Ivanovo': 'Ивановская область',
        'Jaroslavl': 'Ярославская область',
        'Jewish Autonomous Oblast': 'Еврейская автономная область',
        'Kabardino-Balkariya': 'Кабардино-Балкарская Республика',
        'Kaliningrad': 'Калининградская область',
        'Kalmykiya': 'Республика Калмыкия',
        'Kaluga': 'Калужская область',
        'Kamtsjatka': 'Камчатский край',
        'Karachayevo-Cherkesiya': 'Карачаево-Черкесская Республика',
        'Kemerovo': 'Кемеровская область',
        'Khabarovsk Krai': 'Хабаровский край',
        'Khakasiya': 'Республика Хакасия',
        'Khanty-Mansiyskiy Avtonomnyy Okrug': 'Ханты-Мансийский автономный округ',
        'Kharkiv': 'Харьковская область',
        'Kirov': 'Кировская область',
        'Komi Republic': 'Республика Коми',
        'Kostroma': 'Костромская область',
        'Krasnodarskiy': 'Краснодарский край',
        'Krasnoyarskiy': 'Красноярский край',
        'Kurgan': 'Курганская область',
        'Kursk': 'Курская область',
        'Leningrad': 'Ленинградская область',
        'Lipetsk': 'Липецкая область',
        'Luhansk': 'не соответствует ни одному региону России или Украины в списке',
        'Magadan': 'Магаданская область',
        'Mariy-El': 'Республика Марий Эл',
        'Misto Sevastopol': 'Республика Крым (г. Севастополь)',
        'Mordoviya': 'Республика Мордовия',
        'Moscow': 'г. Москва',
        'Moskovskaya': 'Московская область',
        'Murmansk': 'Мурманская область',
        'Nenetskiy Avtonomnyy Okrug': 'Ненецкий автономный округ',
        'Nizjnij Novgorod': 'Нижегородская область',
        'North Ossetia': 'Республика Северная Осетия-Алания',
        'Novgorod': 'Новгородская область',
        'Novosibirsk': 'Новосибирская область',
        'Omsk': 'Омская область',
        'Orenburg': 'Оренбургская область',
        'Orjol': 'Орловская область',
        'Penza': 'Пензенская область',
        'Perm': 'Пермский край',
        'Primorskiy': 'Приморский край',
        'Pskov': 'Псковская область',
        'Republic of Karelia': 'Республика Карелия',
        'Respublika Buryatiya': 'Республика Бурятия',
        'Rjazan': 'Рязанская область',
        'Rostov': 'Ростовская область',
        'Sakha': 'Республика Саха (Якутия)',
        'Sakhalin': 'Сахалинская область',
        'Samara': 'Самарская область',
        'Saratov': 'Саратовская область',
        'Smolensk': 'Смоленская область',
        "Misto Sevastopol'": "Республика Крым",
        "South Karelia": "Республика Карелия",
        "St.-Petersburg": "Ленинградская область",
        "Stavropol'skiy": "Ставропольский край",
        "Sumy": "Нет соответствия",
        "Sverdlovsk": "Свердловская область",
        "Tambov": "Тамбовская область",
        "Tatarstan": "Республика Татарстан",
        "Tjumen": "Тюменская область",
        "Tomsk": "Томская область",
        "Transbaikal Territory": "Забайкальский край",
        "Tula": "Тульская область",
        "Tverskaya": "Тверская область",
        "Tyva": "Республика Тыва",
        "Udmurtiya": "Удмуртская Республика",
        "Ulyanovsk": "Ульяновская область",
        "Vladimir": "Владимирская область",
        "Volgograd": "Волгоградская область",
        "Vologda": "Вологодская область",
        "Voronezj": "Воронежская область",
        'Yamalo-Nenetskiy Avtonomnyy Okrug' : 'ЯНАО'}
    return regions_dict.get(region, region)

milestones['region'] = milestones['region'].apply(translate_region)
milestones_for_fit = milestones.groupby('region')['src_camera'].count().to_frame().reset_index().rename(columns={'region' : 'region_rf', 'src_camera' : 'Количество камер'})
milestones_for_fit
count_intruder = pd.read_excel('/content/drive/MyDrive/Счетная палата/емисс/Количество нарушителей правил дорожного движения.xlsx')
count_intruder

Соединим все выгруженные таблицы:

merged_table = pd.merge(df_group, light_road_for_fit, on="region_rf")
merged_table = pd.merge(merged_table, road_norm[['region_rf', '2021 г.']], on="region_rf")
merged_table = pd.merge(merged_table, milestones_for_fit, on="region_rf")
merged_table = pd.merge(merged_table, count_intruder, on="region_rf")
merged_table = pd.merge(merged_table, improvement_coating[['region_rf', '2021 г.']], on="region_rf")\
.rename(columns={'2021 г._x' : 'road_norm', '2021 г._y' : 'improvement_coating'})
merged_table = merged_table.fillna(0)
merged_table

Сделаем деление на признаки и target, далее обучим модель

X = merged_table[['out_length',
                  'out_defect_prop_count',
                  'out_ligth_prop_count',
                  'out_light_count', 'road_norm',
                  'improvement_coating',
                  'Количество камер',
                  'Количество нарушителей ПДД водителей',
                  'Количество нарушителей ПДД пассажиров',
                  'Количество нарушителей ПДД пешеходов']]
X = X.rename(columns={'out_length' : 'Протяженность освещения',
                      'out_defect_prop_count' : 'Количество опор с деффектами',
                      'out_ligth_prop_count' : 'Количество опор освещения',
                      'out_light_count' : 'Количество светильников',
                      'improvement_coating' : 'Усовершенствованное покрытие',
                      'road_norm' : 'Доля дорог, отвечающих норм-м требованиям'})
y = merged_table.dead_count

scaler = StandardScaler()
model = scaler.fit(X)
X = model.transform(X)

regr = DecisionTreeRegressor(max_depth=3, random_state=12345)
model = regr.fit(X, y)

X = pd.DataFrame(data=X, columns=['Протяженность освещения',
                                  'Количество опор с деффектами',
                                  'Количество опор освещения',
                                  'Количество светильников',
                                  'Доля дорог, отвечающих норм-м требованиям',
                                  'Усовершенствованное покрытие',
                                  'Количество камер',
                                  'Количество нарушителей ПДД водителей',
                                  'Количество нарушителей ПДД пассажиров',
                                  'Количество нарушителей ПДД пешеходов'])
X

Интерпретируем модель с помощью shap

def shap_feature_importance(X, y, model):
    
    """
    Функция для выявления важности признаков с помощью shap_values
    
    Аргументы:
    X -- признаки (numpy array или pandas dataframe)
    y -- таргет (numpy array или pandas series)
    model -- обученная модель
    
    Возвращает:
    shap.summary_plot -- график, отображающий важность каждого признака
    
    """
    
    # Инициализируем Explainer и вычисляем shap_values
    explainer = shap.Explainer(model, X)
    shap_values = explainer(X)
    
    # Получаем родные названия признаков
    feature_names = X.columns if isinstance(X, pd.DataFrame) else None
    
    # Выводим график, отображающий важность каждого признака
    shap.summary_plot(shap_values, X, plot_type="bar", feature_names=feature_names)

# инициализируем и обучаем модель
model = RandomForestRegressor(n_estimators=100, random_state=42)
model.fit(X, y)
shap_feature_importance(X, y, model)

Косвенно, но можем сделать вывод о влиянии топ-3 факторов на количество ДТП.

Комментарии (3)


  1. CrazyElf
    00.00.0000 00:00
    +3

    1) Для моделей, основанных на деревьях, скейлить признаки не нужно. 2) Вы даже не проверили - а выучилась ли чему-то ваша модель, и насколько хорошо. Может она вообще ничему не научилась, а вы пытаетесь анализировать влияние фич. Ни отложенной выборки, ни кросс-валидации, ни даже ну ладно хотя бы просто на трейне скор модели посмотреть. 3) А дальше хорошо было бы сравнить между собой модели разного вида - одинаково ли будут влиять факторы, может у разных моделей разный топ-3 факторов получится, как знать. 4) И регионы между собой тоже интересно было бы сравнить.


  1. xamal
    00.00.0000 00:00

    Вывод: где лучше покрытие, много нарушителей и камер там и больше ДТП?

    Ничего не перепутал?

    Или лучше покрытие - выше скорость, камеры стоят там где много ДТП и камеры мониторят скорость и регистрируют много нарушителей.

    Но скорость в статистике нигде не указывают.


  1. 8akkaunt
    00.00.0000 00:00

    Пролистал целую простыню с надеждой увидеть ответ ПОЧЕМУ так ничего и не увидел !

    Опять как обычно виноват водитель как владелец источника повышенной опасности)