Автор оригинала: FreeCodeCapm Team.
Hari Santanam.
Использование Python и Folium для очистки, анализировать и визуализировать данные о дорожном аварии
Я люблю науку, визуализацию данных и анализ данных. Недавно я исследовал проект, который побудил мой интерес – государственные происшествия.
Научные процессы и задачи и задачи реальной жизни являются вещами, которые должны делать ученые (в самом широком смысле). Это включает в себя сбор, сопоставление, очистку, агрегацию, добавление и удаление деталей данных. Он также включает в себя решение, как проанализировать данные.
И это только первая часть! После этого они должны решить, как представить вывод.
С этим сказанным, вот что я сделал в недавнем проекте.
Я собрал данные о дорожном аварии из штата Нью-Джерси (NJ), США за 2017 год. Это был последний год, для которого были данные на веб-сайте государственного правительства NJ.
Я рад за открытую политику обмена данными с гражданами, хотя организация данных несколько причудливается (мое мнение!), И это не так, как можно ожидать, простым.
Вот шаги, которые я взял на проект:
- Я собрал, очистил и проанализировал данные.
- Данные должны были быть разделены на два подмножества. Один набор имел точные геоконинины, никто не сделал.
- Собрал информацию и подготовленные данные.
- Созданные тепловые карты – статические и со временем, которые показывают несчастные случаи по местоположению, за год, на карте NJ, для визуализации.
Прежде чем идти вперед, я предоставлю некоторый контекст тем, кто не может быть знаком с географией региона.
Государство Нью-Джерси находится на западе Нью-Йорка и простирается на запад и юг (и немного север).
В основном, водители, водители из Нью-Йорка непосредственно до остальных в США (кроме на севере к региону Новой Англии и Канады), должны пройти через NJ. Государство имеет отличное соединение автомагистралей. Он также имеет плотное население пригородных пригородов, и как только вы получите прошедшие километры плотно вязаных старых городов, есть пригородные, пастырские и даже сельские районы.
Приготовление данных и очищение
Вот шаги, которые я взял, чтобы очистить и подготовить набор данных:
- Поиск и исследование данных. Я получил данные с сайта правительства штата Нью-Джерси. Широта и долгота (LAT, Long) являются географическими координатными точками, которые могут отображать места на любой точке на земле. Читать здесь Для получения дополнительной информации о них.
- Я использовал сводные данные для всего государства на 2017 год, последний год, для которого есть данные.
- Существует отдельный файл, который перечисляет заголовки и их описания. Я скопировал файл заголовка в Excel, проанализировал его, затем вставил, что используя текстовый редактор.
Что находят эти шаги?
Из приблизительно 277 000 строк только 700 000 имели широту и долготы (или около 26%).
Это представило проблему. В конце концов, целью проекта состоит в том, чтобы создать визуальное представление наложения данных о несчастных случаях по NJ. Вот что я сделал:
Я разлучил строки без лата, длинные координаты в новых PandaSAframe. Эти строки имели имя города, поэтому я решил сделать отдельную тепловую карту для городов для этих данных.
Таким образом, есть два набора карт тепла: один для набора данных с точными координатами широты и долготы, другой для других данных с только информацией о городах.
Я написал какой-то код, чтобы получить городские латы, длинные координаты для этих данных. Теперь этот набор данных гораздо больше, содержащий 74% от общего количества данных! Это реальные данные – часто неполные и нуждаются в очищении и подготовке.
Смотрите фрагмент кода инициализации ниже.
#TSB - Import Tools, read the file, prep the data#the column names are in a different (pdf)file, so they need to be defined here
#tools below required for drawing the map with data overlayed on it
import folium import folium.plugins as pluginsfrom folium.plugins import HeatMapWithTime
import pandas as pdcolumn_names =['Mumbo-jumbo','County Name','Municipality Name','Crash Date','Crash Day Of Week','Crash Time','Police Dept Code','Police Department','Police Station','Total Killed','Total Injured', 'Pedestrians Killed','Pedestrians Injured','Severity','Intersection','Alcohol Involved','HazMat Involved','Crash Type Code','Total Vehicles Involved','Crash Location','Location Direction', 'Route','Route Suffix','SRI (Std Rte Identifier)','MilePost','Road System','Road Character','Road Horizontal Alignment','Road Grade','Road Surface Type','Surface Condition','Light Condition', 'Environmental Condition','Road Divided By','Temporary Traffic Control Zone','Distance To Cross Street','Unit Of Measurement','Directn From Cross Street','Cross Street Name', 'Is Ramp','Ramp To/From Route Name','Ramp To/From Route Direction','Posted Speed','Posted Speed Cross Street','First Harmful Event','Latitude','Longitude', 'Cell Phone In Use Flag','Other Property Damage','Reporting Badge No']#read the file and load into a dataframedf1 = pd.read_csv('/content/drive/My Drive/Colab/NewJersey2017Accidents.txt', header=None)
Первый шаг (определение набора данных и загрузка контента) теперь выполняется.
Теперь начинается реальная работа. Посмотрим, сколько содержимого отсутствует широта и долготы, которые требуются, чтобы сделать карту.
Мы будем держать записи с хорошими значениями в первом DataFrame DF1
И возьмите записи без лата, длинные значения в другой набор данных DF2
,
Для этого я попытаюсь получить имена городов, чтобы я мог, по крайней мере, определить, на другой карте, показатели несчастных случаев в этих городах без конкретных уличных мест.
Код ниже достигнет этого.
#convert 'Crash Date' field to python pandas readable month/ day/ year format df1['Crash Date'] = pd.to_datetime(df1['Crash Date'], format = '%m/%d/%Y')
#convert Latitude, Longitude columns from string to numericcols_to_convert = ['Latitude', 'Longitude']for col in cols_to_convert: df1[col] = pd.to_numeric(df1[col], errors='coerce')
#Longitude values in the original data didn't have the negative (-) #sign - this code below fixes that by replacing all Lat values with #Lat * -1. Without this, the map displays a totally different part #of the world!df1['Longitude']=df1['Longitude']* -1
#put all records with no data(NaN) for Lat and Long in separate #dataframe (df2)df2 = df1.loc[df1.Latitude.isnull()]#df2 = df1.loc[df1.Latitude.isnull()] & df1.loc[df1.Longitude.isnull()]df2.shape#df2.head()
#drop records with NaN in Lat and Long from df1 (they are saved #above in df2)df1 = df1.dropna(subset=['Latitude','Longitude'])df1.shapeprint(df1.dtypes)
#run some queries on dataframe 1 (with Lat, Long available)#list accidents where one or more person killed — very serious ones#not showing the output here, too longprint(df1.loc[(df1['Total Killed'] >= 1.0), ['Municipality Name','Latitude','Longitude', 'Total Killed']])
#show accidents involving cell phone in useprint(df1.loc[(df1['Cell Phone In Use Flag'] == 'Y'),['Posted Speed','Police Station','Latitude','Longitude']])
#show crashes on Fridaysprint(df1.loc[(df1['Crash Day Of Week'] == 'FR'),['Municipality Name','Posted Speed','Police Station','Latitude','Longitude']])
#show crashes for specific town and speed limitprint(df1.loc[(df1['Municipality Name'] == 'WATCHUNG BORO'), ['Municipality Name','Posted Speed','Police Station','Latitude','Longitude']])
Создать некоторые карты тепла
Давайте получим местоположение на тепловую карту. Мы также можем сделать тепловую карту, чтобы показать изменения со временем.
#define a base map generator function#-note - if folium doesn't work properly(it didn't, at first, for me #:) - in Google Colab - I uninstalled Folium, re-started kernel and #re-installed Folium#I also saved to file as pressing run didn't output results
def generateBaseMap(default_location=[40.5397293,-74.6273494], default_zoom_start=12): base_map = folium.Map(location=default_location, control_scale=True, zoom_start=default_zoom_start) return base_map
base_map = generateBaseMap()base_map
#apply the heat map to the base map from above, and save 'm'(output) # to a file. As explained at the top of the code notes, Run didn't #work for me. I opened saved file in browser to see output
m = HeatMap(data=df_map[['Latitude', 'Longitude', 'count']].groupby(['Latitude','Longitude']).sum().reset_index().values.tolist(), radius=7, max_zoom=10).add_to(base_map)m.save('/content/drive/My Drive/Colab/heatmap.html')
Это хорошо – теперь давайте посмотрим на тепловую карту со временем.
from folium.plugins import HeatMap#first, copy all data [all 2017 county accidents] to our map #dataframedf_map = df1.copy()
#set count field to 1 initially. Then, group by Lat, Long and count #how many are in each set of coordinates to create base map data
df_map['count']=1df_map[['Latitude', 'Longitude', 'count']].groupby(['Latitude', 'Longitude']).sum().sort_values('count', ascending=False).head(10)
base_map = generateBaseMap()base_mapm = HeatMap(data=df_map[['Latitude', 'Longitude', 'count']].groupby(['Latitude','Longitude']).sum().reset_index().values.tolist(), radius=7, max_zoom=10).add_to(base_map)m.save('/content/drive/My Drive/Colab/heatmap_with_time-1.html')
Часть 2 – Создание тепловых карт 2-го набора данных
Ранее мы разделяем набор данных и создали набор данных DF2
Для этих записей без определенной широты и долготных координат.
Причины этого могут быть много. Возможно, данные были загрязнены во время захвата, или сотрудники милиции были слишком заняты с первыми обязанностями респондентов на вкладную точную информацию.
Независимо от причины, давайте получим данные о местонахождении для городов. Это оказалось более сложным, чем я себе представлял. Это может быть просто, чтобы я не думал о оптимальном смысле. Это то, что я сделал это.
В реальных рабочих ситуациях, много времени вам придется пойти на «самым жизнеспособным решением», что означает лучшее, что возможно, приведенное время, экологические ограничения и неполные данные.
#create a list of unique town names from df2 for use later to make a #call to function to get Lat, Long - easy to read each value from a #listtown_names=[]df2.dropna(subset=['Municipality Name'])town_names = df2['Municipality Name'].unique()print(town_names)
Это то, что мы делаем в следующих нескольких шагах. Возьмите список уникальных городов, которые мы только что создали. Затем используйте функцию, чтобы сделать вызов API для Maps.Google
чтобы получить широту и долготу координаты.
Возьмите DataFrame с тарифами городского происшествия, агрегируемые городскими (сгруппированными) и объединяем, что со списком, имеющим lat и длинные координаты, созданные на шаге выше.
Затем позвоните в функцию сюжета, чтобы создать карту тепловую карту, как мы сделали ранее для первого набора данных.
#call a previously created function (listed in the gist - link is #below this code box and output), then store google geo #coordinates #in a csv file.
#Ensure that you have API token:click link to find out how:# Google maps API tokenLat_Long=[]API_KEY = 'YOUR API KEY HERE'for address in town_names: geocode_result = get_google_results(address, API_KEY, return_full_response=RETURN_FULL_RESULTS) Lat_Long.append(geocode_result)
#now, convert the list with our geo coordinates into a csv file that #will be called by another program to overlay on a map.pd.DataFrame(Lat_Long).to_csv('../Colab/town_with_Lat_Long_output.csv', encoding='utf8')
#read the csv file that has the latitude and longitude for the #records in df2, which originally did NOT have lat and longdf6 = pd.read_csv('/content/drive/My Drive/Colab/town_with_Lat_Long_output.csv')df6.shape
#merge the two datasets - one has town names and geo coordinates, #the other has town names and aggregate accident info
df7 = pd.read_csv('/content/drive/My Drive/Colab/df5_output.csv')dfinal = df6.merge(df7, on="Municipality Name", how = 'inner')
#now we draw the heat map for the 2nd dataset finally!
from folium.plugins import HeatMapdef generateBaseMap(default_location=[40.5397293,-74.6273494], default_zoom_start=12): base_map = folium.Map(location=default_location, control_scale=True, zoom_start=default_zoom_start) return base_map
base_map = generateBaseMap()base_mapm = HeatMap(data=dfinal[['latitude', 'longitude', 'count']].groupby(['latitude','longitude']).sum().reset_index().values.tolist(), radius=7, max_zoom=10).add_to(base_map)m.save('/content/drive/My Drive/Colab/heatmap_town_total_accidents_2017.html')
Гист для кода это здесь Отказ
Спасибо за чтение до конца. Если вы новичок, каждый проект науки данных – это приключение – повесить там. Неожиданные (и ожидаемые) проблемы возникнут – но и ваша изобретательность, талант и применение других опытов кодер, чтобы добраться до решений, которые вы ищете.
Пожалуйста, дайте мне хлопок, если вам понравилась статья!