УГЛУБЛЕННЫЙ АНАЛИЗ

Повесть о двух городах

Кластеризация районов Лондона и Парижа с использованием машинного обучения

Введение

Повесть о двух городах, роман, написанный Чарльзом Диккенсом, происходит в Лондоне и Париже, действие которого происходит во время Французской революции. Эти города существовали тогда и сейчас. С годами многое изменилось, и теперь мы посмотрим, как выросли города.

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

Бизнес-проблема

Цель состоит в том, чтобы помочь туристам выбрать направление в зависимости от впечатлений, которые могут предложить окрестности, и того, что они хотели бы получить. Эта модель также помогает людям принимать решения, если они думают о переезде в Лондон или Париж или даже если они хотят переехать в другие районы города. Наши результаты помогут заинтересованным сторонам принимать обоснованные решения и решать любые проблемы, которые у них есть, включая различные виды кухни, продовольственные магазины и то, что может предложить город.

Описание данных

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

Лондон

Чтобы получить наше решение, мы очищаем наши данные от https://en.wikipedia.org/wiki/List_of_areas_of_London

На этой странице Википедии есть информация обо всех районах; мы ограничиваемся Лондоном.

  1. район: название района.
  2. город: название района.
  3. post_code: почтовые индексы Лондона.

На этой странице Википедии отсутствует информация о географических положениях. Для решения этой проблемы мы используем ArcGIS API.

ArcGIS API

ArcGIS Online позволяет связывать людей, местоположения и данные с помощью интерактивных карт. Работайте с интеллектуальными стилями на основе данных и интуитивно понятными инструментами анализа, которые обеспечивают аналитику местоположения. Поделитесь своими мыслями со всем миром или конкретными группами.

В частности, мы используем ArcGIS для получения географических местоположений окрестностей Лондона. Добавление следующих столбцов к нашему начальному набору данных подготавливает наши данные.

  1. latitude: широта для района.
  2. longitude: долгота для района.

Париж

Для разработки решения мы используем данные JSON, доступные по адресу https://www.data.gouv.fr/fr/datasets/r/e88c6fda-1d09-42a0-a069-606d3259114e

Файл JSON содержит данные обо всех районах Франции; мы ограничиваемся Парижем.

  1. postal_code: почтовые индексы Франции.
  2. nom_comm: название районов во Франции.
  3. nom_dept: название районов, эквивалентных городам во Франции.
  4. geo_point_2d: кортеж, содержащий широту и долготу районов.

Данные Foursquare API

Нам понадобятся данные о разных заведениях в разных районах этого района. Чтобы получить эту информацию, мы будем использовать информацию о местоположении «Foursquare». Foursquare - это поставщик данных о местоположении с информацией о всевозможных местах и ​​событиях в интересующей области. Такая информация включает названия заведений, их расположение, меню и даже фотографии. Таким образом, платформа определения местоположения Foursquare будет использоваться в качестве единственного источника данных, поскольку вся указанная необходимая информация может быть получена через API.

Найдя список районов, мы подключаемся к Foursquare API, чтобы собрать информацию о местах внутри каждого района. Для каждого района мы выбрали радиус 500 метров.

Данные, полученные из Foursquare, содержали информацию о местах проведения в пределах указанного расстояния долготы и широты почтовых индексов. Информация, полученная по каждому объекту, выглядит следующим образом:

  1. Район: название района.
  2. Широта района: Широта района.
  3. Долгота района: долгота района.
  4. Место проведения: название места проведения.
  5. Широта места: Широта места проведения.
  6. Долгота места проведения: долгота места проведения.
  7. Категория объекта: Категория объекта.

Основываясь на всей информации, собранной как для Лондона, так и для Парижа, у нас есть достаточно данных для построения нашей модели. Мы группируем районы вместе на основе схожих категорий заведений. Затем мы представляем наши наблюдения и выводы. Используя эти данные, наши заинтересованные стороны могут принять необходимое решение.

Методология

Мы будем создавать нашу модель с помощью Python, поэтому начнем с импорта всех необходимых пакетов. Код доступен на GitHub, чтобы следить за ним.

import pandas as pd
import requests
import numpy as np
import matplotlib.cm as cm
import matplotlib.colors as colors
import folium
from sklearn.cluster import KMeans

Разбивка пакета:

  • Pandas: для сбора и обработки данных в JSON и HTML, а затем анализа данных.
  • запросы: обработка HTTP-запросов.
  • matplotlib: детализация сгенерированных карт.
  • folium: создание карт Лондона и Парижа.
  • sklearn: для импорта модели машинного обучения K Means.

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

Сбор данных

На этапе сбора данных мы начинаем со сбора необходимых данных для городов Лондон и Париж. Нам нужны данные с почтовыми индексами, районами и районами, характерными для каждого из городов.

Чтобы собрать данные для Лондона с помощью панд, мы соскребаем страницу со списком областей Лондона в Википедии, чтобы взять вторую таблицу:

url_london = "https://en.wikipedia.org/wiki/List_of_areas_of_London"
wiki_london_url = requests.get(url_london)
wiki_london_data = pd.read_html(wiki_london_url.text)
wiki_london_data = wiki_london_data[1]
wiki_london_data
  1. nom_comm: название районов во Франции.
  2. nom_dept: название районов, эквивалентных городам во Франции.
  3. geo_point_2d: кортеж, содержащий широту и долготу районов.

Данные Foursquare API

Нам понадобятся данные о разных заведениях в разных районах этого района. Чтобы получить эту информацию, мы будем использовать информацию о местоположении «Foursquare». Foursquare - это поставщик данных о местоположении с информацией о всевозможных местах и ​​событиях в интересующей области. Такая информация включает названия заведений, их расположение, меню и даже фотографии. Таким образом, платформа определения местоположения Foursquare будет использоваться в качестве единственного источника данных, поскольку вся указанная необходимая информация может быть получена через API.

Найдя список районов, мы подключаемся к Foursquare API, чтобы собрать информацию о местах внутри каждого района. Для каждого района мы выбрали радиус 500 метров.

Данные, полученные из Foursquare, содержали информацию о местах проведения в пределах указанного расстояния долготы и широты почтовых индексов. Информация, полученная по каждому объекту, следующая:

  1. Район: название района.
  2. Широта района: Широта района.
  3. Долгота района: долгота района.
  4. Место проведения: название места проведения.
  5. Широта места: Широта места проведения.
  6. Долгота места проведения: долгота места проведения.
  7. Категория объекта: Категория объекта.

Основываясь на всей информации, собранной как для Лондона, так и для Парижа, у нас есть достаточно данных для построения нашей модели. Мы группируем районы вместе на основе схожих категорий заведений. Затем мы представляем наши наблюдения и выводы. Используя эти данные, наши заинтересованные стороны могут принять необходимое решение.

Методология

Мы будем создавать нашу модель с помощью Python, поэтому начнем с импорта всех необходимых пакетов. Код доступен на GitHub, чтобы следить за ним.

import pandas as pd
import requests
import numpy as np
import matplotlib.cm as cm
import matplotlib.colors as colors
import folium
from sklearn.cluster import KMeans

Разбивка пакета:

  • Pandas: для сбора и обработки данных в JSON и HTML, а затем анализа данных.
  • запросы: обработка HTTP-запросов.
  • matplotlib: детализация сгенерированных карт.
  • folium: создание карт Лондона и Парижа.
  • sklearn: для импорта модели машинного обучения K Means.

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

Сбор данных

На этапе сбора данных мы начинаем со сбора необходимых данных для городов Лондон и Париж. Нам нужны данные с почтовыми индексами, районами и районами, характерными для каждого из городов.

Чтобы собрать данные для Лондона с помощью панд, мы соскребаем страницу со списком областей Лондона в Википедии, чтобы взять вторую таблицу:

url_london = "https://en.wikipedia.org/wiki/List_of_areas_of_London"
wiki_london_url = requests.get(url_london)
wiki_london_data = pd.read_html(wiki_london_url.text)
wiki_london_data = wiki_london_data[1]
wiki_london_data

Данные выглядят так:

Для сбора данных по Парижу мы загружаем файл JSON, содержащий все почтовые индексы Франции, по адресу https://www.data.gouv.fr/fr/datasets/r/e88c6fda-1d09-42a0-a069-606d3259114e

Используя Pandas, загружаем таблицу после чтения файла JSON:

!wget -q -O 'france-data.json' https://www.data.gouv.fr/fr/datasets/r/e88c6fda-1d09-42a0-a069-606d3259114e
print("Data Downloaded!")
paris_raw = pd.read_json('france-data.json')
paris_raw.head()

Предварительная обработка данных

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

wiki_london_data.rename(columns=lambda x: x.strip().replace(" ", "_"), inplace=True)
wiki_london_data['borough'] = wiki_london_data['borough'].map(lambda x: x.rstrip(']').rstrip('0123456789').rstrip('['))

Для Парижа мы разбиваем каждое из вложенных полей и создаем необходимый нам фрейм данных:

paris_field_data = pd.DataFrame()
for f in paris_raw.fields:
    dict_new = f
    paris_field_data = paris_field_data.append(dict_new, ignore_index=True)
 
paris_field_data.head()

Выбор функции

Для обоих наших наборов данных нам нужны только район, район, почтовые индексы и геолокации (широта и долгота). В итоге мы выбираем нужные нам столбцы:

df1 = wiki_london_data.drop( [ wiki_london_data.columns[0], wiki_london_data.columns[4], wiki_london_data.columns[5] ], axis=1)
 
df_2 = paris_field_data[['postal_code','nom_comm','nom_dept','geo_point_2d']]

Функциональная инженерия

Оба наших набора данных содержат информацию, относящуюся ко всем городам страны. Мы можем сузить и обработать данные, выбрав только районы «Лондон» и «Париж».

df1 = df1[df1['town'].str.contains('LONDON')]
 
df_paris = df_2[df_2['nom_dept'].str.contains('PARIS')].reset_index(drop=True)

Просматривая наш набор данных по Лондону, мы видим, что у нас нет данных о геолокации. Нам нужно экстраполировать недостающие данные на наши районы. Мы делаем это, используя ArcGIS API. С помощью ArcGIS API мы можем получить данные о широте и долготе нашего района Лондона.

from arcgis.geocoding import geocode
from arcgis.gis import GIS
gis = GIS()

Определение функции London ArcGIS geocode для возврата широты и долготы.

def get_x_y_uk(address1):
   lat_coords = 0
   lng_coords = 0
   g = geocode(address='{}, London, England, GBR'.format(address1))[0]
   lng_coords = g['location']['x']
   lat_coords = g['location']['y']
   return str(lat_coords) +","+ str(lng_coords)

Передача почтовых индексов Лондона для получения географических координат

coordinates_latlng_uk = geo_coordinates_uk.apply(lambda x: get_x_y_uk(x))

Мы продолжаем слияние наших исходных данных с географическими координатами, чтобы подготовить наш набор данных к следующему этапу.

london_merged = pd.concat([df1,lat_uk.astype(float), lng_uk.astype(float)], axis=1)
london_merged.columns= ['borough','town','post_code','latitude','longitude']
london_merged

Что касается нашего набора данных Paris, нам не нужно получать географические координаты с помощью внешнего источника данных или собирать их с помощью вызова ArcGIS API, поскольку они уже сохранены в столбце geo_point_2d в виде кортежа в фрейм данных df_paris.

Нам просто нужно извлечь из столбца широту и долготу:

paris_lat = paris_latlng.apply(lambda x: x.split(',')[0])
paris_lat = paris_lat.apply(lambda x: x.lstrip('['))
 
paris_lng = paris_latlng.apply(lambda x: x.split(',')[1])
paris_lng = paris_lng.apply(lambda x: x.rstrip(']'))
 
paris_geo_lat  = pd.DataFrame(paris_lat.astype(float))
paris_geo_lat.columns=['Latitude']
 
paris_geo_lng = pd.DataFrame(paris_lng.astype(float))
paris_geo_lng.columns=['Longitude']

Затем мы создаем наш набор данных Paris с необходимой информацией:

paris_combined_data = pd.concat([df_paris.drop('geo_point_2d', axis=1), paris_geo_lat, paris_geo_lng], axis=1)
paris_combined_data

Примечание. Оба набора данных были правильно обработаны и отформатированы. Поскольку одни и те же шаги применяются к наборам данных Лондона и Парижа, мы будем обсуждать код только для набора данных Лондона для простоты.

Визуализация окрестностей Лондона и Парижа

Теперь, когда наши наборы данных готовы, с помощью пакета Folium мы можем визуализировать карты Лондона и Парижа с районами, которые мы собрали.

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

Вот где в игру вступает Foursquare. С помощью Foursquare мы определяем функцию, которая собирает информацию, относящуюся к каждому району, включая название района, географические координаты, места проведения и категории мест проведения.

LIMIT=100
 
def getNearbyVenues(names, latitudes, longitudes, radius=500):
 
    venues_list=[]
    for name, lat, lng in zip(names, latitudes, longitudes):
        print(name)
 
        # create the API request URL
        url = 'https://api.foursquare.com/v2/venues/explore?&client_id={}&client_secret={}&v={}&ll={},{}&radius={}&limit={}'.format(
            CLIENT_ID, 
            CLIENT_SECRET, 
            VERSION, 
            lat, 
            lng, 
            radius,
            LIMIT
            )
 
        # make the GET request
        results = requests.get(url).json()["response"]['groups'][0]['items']
 
        # return only relevant information for each nearby venue
        venues_list.append([(
            name, 
            lat, 
            lng, 
            v['venue']['name'], 
            v['venue']['categories'][0]['name']) for v in results])
 
    nearby_venues = pd.DataFrame([item for venue_list in venues_list for item in venue_list])
    nearby_venues.columns = ['Neighbourhood', 
                  'Neighbourhood Latitude', 
                  'Neighbourhood Longitude', 
                  'Venue', 
                  'Venue Category']
 
    return(nearby_venues)

Одно горячее кодирование

Поскольку мы пытаемся выяснить, какие виды категорий заведений присутствуют в каждом районе, а затем вычислить 10 наиболее распространенных мест, чтобы основать наше сходство, мы используем One Hot Encoding для работы с нашим категориальным типом данных категорий мест проведения. . Это помогает преобразовать категориальные данные в числовые.

Мы не будем использовать кодирование меток в этой ситуации, поскольку кодирование меток может привести к смещению в нашей модели машинного обучения или ранжированию, которого мы пытаемся избежать с помощью One Hot Encoding.

Мы выполняем однократное кодирование, а затем вычисляем среднее значение сгруппированных категорий мест для каждого из районов.

# One hot encoding
London_venue_cat = pd.get_dummies(venues_in_London[['Venue Category']], prefix="", prefix_sep="")
 
# Adding neighbourhood to the mix
London_venue_cat['Neighbourhood'] = venues_in_London['Neighbourhood'] 
 
# moving neighborhood column to the first column
fixed_columns = [London_venue_cat.columns[-1]] + list(London_venue_cat.columns[:-1])
London_venue_cat = London_venue_cat[fixed_columns]
 
# Grouping and calculating the mean
London_grouped = London_venue_cat.groupby('Neighbourhood').mean().reset_index()

Лучшие места в окрестностях

На следующем этапе нам нужно отсортировать, ранжировать и маркировать самые популярные категории заведений в нашем районе.

Давайте определим функцию для получения лучших категорий заведений в округе.

def return_most_common_venues(row, num_top_venues):
    row_categories = row.iloc[1:]
    row_categories_sorted = row_categories.sort_values(ascending=False)
 
    return row_categories_sorted.index.values[0:num_top_venues]

Есть много категорий, мы рассмотрим 10 самых популярных категорий, чтобы избежать перекоса данных.

Определение функции для точной маркировки

num_top_venues = 10
 
indicators = ['st', 'nd', 'rd']
 
# create columns according to number of top venues
columns = ['Neighbourhood']
for ind in np.arange(num_top_venues):
    try:
        columns.append('{}{} Most Common Venue'.format(ind+1, indicators[ind]))
    except:
        columns.append('{}th Most Common Venue'.format(ind+1))

Получение лучших категорий заведений в окрестностях Лондона

# create a new dataframe for London
neighborhoods_venues_sorted_london = pd.DataFrame(columns=columns)
neighborhoods_venues_sorted_london['Neighbourhood'] = London_grouped['Neighbourhood']
 
for ind in np.arange(London_grouped.shape[0]):
    neighborhoods_venues_sorted_london.iloc[ind, 1:] = return_most_common_venues(London_grouped.iloc[ind, :], num_top_venues)
 
neighborhoods_venues_sorted_london.head()

Построение модели - K-средства

Переходим к самой захватывающей части - Построение модели! Мы будем использовать алгоритм машинного обучения кластеризации K-средств для кластеризации похожих районов вместе. Есть много разных размеров кластеров, которые мы можем выбрать, мы выберем количество кластеров, равное 5, чтобы сохранить его как можно более оптимальным.

# set number of clusters
k_num_clusters = 5
 
London_grouped_clustering = London_grouped.drop('Neighbourhood', 1)
 
# run k-means clustering
kmeans_london = KMeans(n_clusters=k_num_clusters, random_state=0).fit(London_grouped_clustering)

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

neighborhoods_venues_sorted_london.insert(0, 'Cluster Labels', kmeans_london.labels_ +1)

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

london_data = london_merged
 
london_data = london_data.join(neighborhoods_venues_sorted_london.set_index('Neighbourhood'), on='borough')
 
london_data.head()

Визуализация сгруппированных окрестностей

Наши данные обрабатываются, недостающие данные собираются и компилируются. Модель построена. Остается только увидеть на карте сгруппированные районы. Опять же, для этого мы используем пакет Folium.

Мы отбрасываем все значения NaN (Not a Number), чтобы предотвратить перекос данных

london_data_nonan = london_data.dropna(subset=['Cluster Labels'])

Изучение наших кластеров

Мы могли бы исследовать наши кластеры, расширив наш код, используя столбец Cluster Labels:

Кластер 1

london_data_nonan.loc[london_data_nonan['Cluster Labels'] == 1, london_data_nonan.columns[[1] + list(range(5, london_data_nonan.shape[1]))]]

Кластер 2

london_data_nonan.loc[london_data_nonan['Cluster Labels'] == 2, london_data_nonan.columns[[1] + list(range(5, london_data_nonan.shape[1]))]]

Кластер 3

london_data_nonan.loc[london_data_nonan['Cluster Labels'] == 3, london_data_nonan.columns[[1] + list(range(5, london_data_nonan.shape[1]))]]

Кластер 4

london_data_nonan.loc[london_data_nonan['Cluster Labels'] == 4, london_data_nonan.columns[[1] + list(range(5, london_data_nonan.shape[1]))]]

Кластер 5

london_data_nonan.loc[london_data_nonan['Cluster Labels'] == 5, london_data_nonan.columns[[1] + list(range(5, london_data_nonan.shape[1]))]]

Результаты и обсуждение

Районы Лондона очень многокультурны. Есть много разных кухонь, включая индийскую, итальянскую, турецкую и китайскую. Лондон, кажется, делает еще один шаг в этом направлении, располагая множеством ресторанов, баров, фреш-баров, кафе, магазинов Fish and Chips и мест для завтрака. Здесь также есть много вариантов для покупок: блошиные рынки, цветочные магазины, рыбные рынки, рыболовные магазины, магазины одежды. Похоже, что основными видами транспорта являются автобусы и поезда. Для досуга в окрестностях есть множество парков, полей для гольфа, зоопарка, тренажерных залов и исторических мест. В целом, Лондон предлагает мультикультурный, разнообразный и, безусловно, развлекательный опыт.

Географически Париж относительно невелик. Он предлагает широкий выбор кухонь и закусочных, включая французскую, тайскую, камбоджийскую, азиатскую, китайскую и т. Д. Есть много мест для встреч, включая множество ресторанов и баров. В Париже много бистро. Различные виды общественного транспорта в Париже, включая автобусы, велосипеды, лодки или паромы. Для отдыха и осмотра достопримечательностей есть множество площадей, троп, парков, исторических мест, магазинов одежды, художественных галерей и музеев. В целом, Париж кажется расслабляющим местом для отдыха с множеством озер, исторических мест и широким выбором кухонь, которые можно попробовать.

Вывод

Целью этого проекта было исследовать города Лондона и Парижа и увидеть, насколько они привлекательны для потенциальных туристов и мигрантов. Мы исследовали оба города на основе их почтовых индексов, а затем экстраполировали общие места проведения мероприятий, присутствующие в каждом из кварталов, в конце концов, сгруппировав похожие районы вместе.

Мы могли видеть, что каждый район в обоих городах предлагает широкий спектр впечатлений, которые по-своему уникальны. Культурное разнообразие совершенно очевидно, что также дает ощущение приобщенности.

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

Подробный код доступен на GitHub. Спасибо за чтение!

использованная литература

  1. Битва за окрестности - взгляд на мой Лондон, Дайо Джон
  2. Битва кварталов! Где я могу начать свой ресторанный бизнес в Париже лучше всего? Закария БУЗИАН
  3. Foursquare API
  4. ArcGIS API