Введение

Крикет - популярный вид спорта, особенно в таких азиатских странах, как Индия, Пакистан, Шри-Ланка, Бангладеш и т. Д. В результате глобализации многие поклонники крикета, переехавшие в Канаду, не могут смотреть спорт по телевизору или летать на тысячи километров. на стадион. Таким образом, чтобы по-настоящему почувствовать себя фанатами спорта, часто возникает желание посмотреть игру на стадионе, который находится поблизости от них. Чтобы воспользоваться этой возможностью и удовлетворить поклонников крикета в Канаде.

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

Постановка задачи

Заказчик, то есть доска для крикета Канады, хочет найти лучшее место для строительства стадиона при следующих условиях / критериях:

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

Сбор данных

  1. Чтобы соответствовать четвертому критерию, нам нужны данные о популярных заведениях поблизости. Мы используем Foursquare API для изучения популярных мест в разных районах Торонто и их окрестностях. Foursquare - это социальная сеть, доступная для обычных смартфонов, включая iPhone, BlackBerry и телефоны на базе Android. Чтобы использовать Foursquare на этих устройствах, загрузите бесплатное приложение. Цель приложения - помочь вам найти и поделиться информацией о предприятиях и достопримечательностях вокруг вас. А его версия API помогает разработчикам программного обеспечения создавать приложения или исследовать их в целях исследований и разработок.
  2. Чтобы понять прибыльность стадиона, мы используем иммиграционные данные для анализа количества иммигрантов-фанатов крикета и их тенденций в ближайшем будущем. Мы используем иммиграционные данные ООН. С официального сайта ООН используются иммиграционные данные для Канады из других стран.
  3. Названия районов, а также соответствующие им районы и почтовые индексы взяты из Википедии: (https://en.wikipedia.org/w/index.php?title=List_of_postal_codes_of_Canada:_M&oldid=945633050)
  4. Данные переписи населения Торонто по его социально-демографическим характеристикам, таким как общая численность населения, средняя арендная плата арендатора, семейный доход и население Южной Азии для удовлетворения первых трех критериев требований клиентов, будут взяты из профиля района Торонто (https://bit.ly/3airrOJ)

Рассмотрение:

  1. Население Южной Азии в Канаде - это выходцы из Индии, Пакистана, Афганистана, Шри-Ланки и Бангладеш. Поскольку все эти страны любят крикет, мы определяем их как нашу основную целевую аудиторию.
  2. Средняя арендная плата арендатора как индикатор стоимости земли в районе
    Для визуализации районов на интерактивной карте мы получаем данные о географических координатах каждого района: (https://cocl.us/Geospatial_data)

Импорт и установка необходимых библиотек

import numpy as np  # useful for many scientific computing in Python
import pandas as pd # primary data structure library
!conda install -c anaconda xlrd --yes
import matplotlib.pyplot as plt
import pylab as pl
from sklearn.preprocessing import PolynomialFeatures
from sklearn import linear_model
!conda install lxml --yes
!conda install scikit-learn==0.20.0  --yes
!conda install -c districtdatalabs yellowbrick  --yes

Получение иммиграционных данных Канады

df_can = pd.read_excel('https://s3-api.us-geo.objectstorage.softlayer.net/cf-courses-data/CognitiveClass/DV0101EN/labs/Data_Files/Canada.xlsx',
                       sheet_name='Canada by Citizenship',
                       skiprows=range(20),
                       skipfooter=2
                      )
print('Data downloaded and read into a dataframe!')
df_can.head()

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

years = list(map(int,range(1980, 2014)))
dfi=df_can[df_can['OdName']=='India']
dfi=dfi[years]

Дальнейшая фильтрация данных, создание итоговой колонки для определения топ-5 национальностей иммигрантов.

df_can.drop(['AREA', 'REG', 'DEV', 'Type', 'Coverage'], axis=1, inplace=True)
df_can.rename(columns={'OdName':'Country', 'AreaName':'Continent','RegName':'Region'}, inplace=True)
df_can.set_index('Country', inplace=True)
df_can['Total'] = df_can.sum(axis=1)
df_can.sort_values(['Total'], ascending=False, axis=0, inplace=True)
# get the top 5 entries
df_top5 = df_can.head()
# transpose the dataframe
df_top5 = df_top5[years].transpose() 
df_top5.head()

Визуализация тенденции этих иммигрантов в Канаде

df_top5.index = df_top5.index.map(int) # let's change the index values of df_top5 to type integer for plotting
df_top5.plot(kind='area', 
             stacked= True,
             figsize=(20, 10), # pass a tuple (x, y) size
             )
plt.title('Immigration Trend of Top 5 Countries')
plt.ylabel('Number of Immigrants')
plt.xlabel('Years')
plt.show()

Мы наблюдаем, что, за исключением Соединенного Королевства Великобритании и Северной Ирландии, иммиграция из других стран увеличивается из года в год. Таким образом, в настоящее время количество иммигрантов больше.

Уточняя структуру данных об иммигрантах для Индии, мы обобщаем и прогнозируем будущую тенденцию иммигрантов в Канаду. Индия выбрана из-за постоянной и высокой иммиграции. А главное из-за любви индейцев к крикету.

dfi = dfi.rename(columns={' ': 'years'}, index={79: 'Number of Immigrants'})
dfin=pd.DataFrame(dfi.loc['Number of Immigrants'])
dfin.reset_index(inplace=True)
dfin=dfin.rename(columns={'index':'Year'})

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

Разделение данных на обучающий набор и набор для тестирования

msk = np.random.rand(len(dfin)) < 0.8
train = dfin[msk]
test = dfin[~msk]

Подгонка кривой полиномиальной регрессии степени 2

train_x = np.asanyarray(train[['Year']])
train_y = np.asanyarray(train[['Number of Immigrants']])
test_x = np.asanyarray(test[['Year']])
test_y = np.asanyarray(test[['Number of Immigrants']])

poly = PolynomialFeatures(degree=2)
train_x_poly = poly.fit_transform(train_x)

Получите коэффициенты и точку пересечения подобранной кривой регрессии.

clf = linear_model.LinearRegression()
train_y_ = clf.fit(train_x_poly, train_y)
# The coefficients
print ('Coefficients: ', clf.coef_)
print ('Intercept: ',clf.intercept_)

Вывод:

Coefficients:  [[ 0.00000000e+00  3.65139354e+04 -8.90910318e+00]]
Intercept:  [-37366766.63733578]

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

plt.scatter(train.Year, train['Number of Immigrants'],  color='blue')
XX = np.arange(1980, 2021, 0.1)
yy = clf.intercept_[0]+ clf.coef_[0][1]*XX+ clf.coef_[0][2]*np.power(XX, 2)
plt.plot(XX, yy, '-r' )
plt.xlabel("Year")
plt.ylabel("Number of Immigrants")

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

Проверка точности подобранной модели

from sklearn.metrics import r2_score
test_x_poly = poly.fit_transform(test_x)
test_y_ = clf.predict(test_x_poly)
print("Mean absolute error: %.2f" % np.mean(np.absolute(test_y_ - test_y)))
print("Residual sum of squares (MSE): %.2f" % np.mean((test_y_ - test_y) ** 2))
print("R2-score: %.2f" % r2_score(test_y_ , test_y) )
Mean absolute error: 3206.77
Residual sum of squares (MSE): 14704888.56
R2-score: 0.77

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

Импорт данных переписи, обработанных и полученных с публичного портала Торонто

Рассмотрение:

  1. Население Южной Азии в Канаде - это выходцы из Индии, Пакистана, Афганистана, Шри-Ланки и Бангладеш. Поскольку все эти страны любят крикет, мы определяем их как нашу основную целевую аудиторию.
  2. Средняя арендная плата арендатора как показатель стоимости земли в микрорайоне
dft=pd.read_csv('wbtoronto.csv')
dft.rename(columns={'   South Asian': 'South Asian'}, inplace=True)
dft.drop(['Combined Indicators'],axis=1,inplace=True)
dft.head()

Чтение геопространственных данных для получения координат каждого района

df_geo = pd.read_csv("https://cocl.us/Geospatial_data")
df_geo

103 строки × 3 столбца

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

df = pd.read_html('https://en.wikipedia.org/w/index.php?title=List_of_postal_codes_of_Canada:_M&oldid=945633050')[0]
df = df[df.Borough!='Not assigned']
df = pd.merge(df, df_geo, left_on='Postcode', right_on='Postal Code').drop(['Postal Code', 'Postcode', 'Borough'], axis=1)
df = pd.merge(df, dft, on='Neighbourhood', how='left').dropna(how='any', axis=0).reset_index(drop=True)
df.head()

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

df['Percentage of South Asian'] = df['South Asian'] / df['Total Population'] * 100
df.drop(['Total Population', 'South Asian'], axis=1, inplace=True)
df.head()

Получение координат Торонто с помощью geopy

# get location of Toronto using geopy
!conda install -c conda-forge geopy --yes
from geopy.geocoders import Nominatim
address = 'Toronto'
geolocator = Nominatim(user_agent='to_explorer')
location = geolocator.geocode(address)
latitude = location.latitude
longitude = location.longitude
print("The geographical coordinates of Toronto are {}, {}".format(latitude, longitude))
The geographical coordinates of Toronto are 43.6534817, -79.3839347

Визуализация Торонто и всех его окрестностей с помощью Folium

# Folium mapping
import folium
map_Toronto = folium.Map(location=[latitude, longitude], zoom_start=10)

# add markers to map
for lat, lng, neighbourhood in zip(df['Latitude'], df['Longitude'], df['Neighbourhood']):
  label = '{}'.format(neighbourhood)
  label = folium.Popup(label)
  folium.CircleMarker(
      [lat,lng],
      radius=8,
      color='blue',
      popup=label,
      fill_color='#3186cc',
      fill_opacity=0.7,
      fill=True

  ).add_to(map_Toronto)

map_Toronto

Использование Foursquare API для поиска популярных заведений в каждом районе

Ввод моих личных учетных данных Foursquare

CLIENT_ID = 'Q2BJSOVMV25YXYYJGC4LJKP1GX2K4KEQV4DOAQSUKN4UT2AZ' # your Foursquare ID
CLIENT_SECRET = 'A0YVEMDTY3HXHZRUVUGVUACEJM055MZGEIFSO4V0KLAIBUBG' # your Foursquare Secret
VERSION = '20180605' # Foursquare API version

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

import requests
LIMIT = 100
radius = 1500
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
    )
def getNearbyVenues(names, latitudes, longitudes, radius=1500):
  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']['location']['lat'],
        v['venue']['location']['lng'],
        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 Latitude',
                           'Venue Longitude',
                           'Venue Category']
  return(nearby_venues)

Вызов указанной выше функции для получения данных по окрестностям в df Dataframe

toronto_venues = getNearbyVenues(names=df['Neighbourhood'],
                                 latitudes=df['Latitude'],
                                 longitudes=df['Longitude'])
toronto_venues
Victoria Village
Rouge
Malvern
Highland Creek
Flemingdon Park
Humewood-Cedarvale
Markland Wood
Guildwood
Morningside
West Hill
The Beaches
Woburn
Hillcrest Village
Bathurst Manor
Thorncliffe Park
Scarborough Village
Henry Farm
Little Portugal
Ionview
Kennedy Park
Bayview Village
Oakridge
Humber Summit
Cliffcrest
Mount Dennis
Weston
Dorset Park
Forest Hill North
Willowdale West
Roncesvalles
Agincourt North
Milliken
New Toronto
Alderwood
Long Branch

Полученный результат Foursquare используется для подсчета количества популярных заведений рядом с каждым районом.

toronto_grouped=toronto_venues.groupby('Neighbourhood').count()

Участок квартала и количество популярных заведений в нем

toronto_grouped.sort_values(by='Venue', ascending=False, inplace=True)
%matplotlib inline
import matplotlib as mpl
import matplotlib.pyplot as plt
mpl.style.use('ggplot')
toronto_grouped['Venue'].plot(kind='bar', figsize=(15,5))
plt.title('Number of popular venues in Each Neighbourhood in Toronto')
plt.xlabel('Neighbourhood')
plt.ylabel('Number of popular venues')
plt.show()

График соседства с процентным соотношением выходцев из Южной Азии

df_ethnic = df[['Neighbourhood', 'Percentage of South Asian']].set_index('Neighbourhood')
# sort by descending order
df_ethnic.sort_values(by='Percentage of South Asian', ascending=False, inplace=True)
#plot bar graph
df_ethnic.plot(kind='bar', figsize=(13,5))
plt.title('Distribution of South Asians in Each Neighbourhood')
plt.xlabel('Neighbourhood')
plt.ylabel('Percentage of South Asian')
plt.show()

График зависимости от среднего семейного дохода после уплаты налогов

df_income = df[['Neighbourhood', 'After-Tax Household Income']].set_index('Neighbourhood')
# sort by descending order
df_income.sort_values(by='After-Tax Household Income', ascending=False, inplace=True)
#plot bar graph
df_income.plot(kind='bar', figsize=(13,5))
plt.title('Distribution of Median Household Income in Each Neighbourhood')
plt.xlabel('Neighbourhood')
plt.ylabel('Median Household Income')
plt.show()

График зависимости от средней арендной платы арендатора

df_rent = df[['Neighbourhood', 'Tenant Average Rent']].set_index('Neighbourhood')
# sort by descending order
df_rent.sort_values(by='Tenant Average Rent', ascending=False, inplace=True)
#plot bar graph
df_rent.plot(kind='bar', figsize=(13,5))
plt.title('Distribution of Tenant Average Rent in Each Neighbourhood')
plt.xlabel('Neighbourhood')
plt.ylabel('Tenant Average Rent')
plt.show()

Данные из Foursquare объединяются с исходными данными для формирования кадра данных df_final для кластеризации.

df_final = pd.merge(df, toronto_grouped, on='Neighbourhood')

Нежелательные столбцы отбрасываются

df_final.drop(['Neighbourhood Id','Neighbourhood Longitude','Neighbourhood Latitude','Venue Latitude','Venue Longitude','Venue Category'],axis=1,inplace=True)
df_final.head()

Кластеризация окрестностей

Нормализация по стандартному отклонению

Теперь давайте нормализуем набор данных. Но зачем вообще нужна нормализация? Нормализация - это статистический метод, который помогает математическим алгоритмам одинаково интерпретировать признаки с разными величинами и распределениями. Мы используем StandardScaler () для нормализации нашего набора данных.

from sklearn.preprocessing import StandardScaler
X = df_final.values[:,3:]
X = np.nan_to_num(X)
Clus_dataSet = StandardScaler().fit_transform(X)
df_normalized = pd.DataFrame(Clus_dataSet)
df_normalized.rename(columns={0:'Tenant Average Rent', 1:'After-Tax Household Income', 2:'Percentage of South Asian', 3:'Number of Popular Venues'}, inplace=True)
df_normalized.head()

Нахождение оптимального количества кластеров, k

Итак, как мы можем выбрать правильное значение для K? Общее решение - зарезервировать часть ваших данных для проверки точности модели. Затем выберите k = 1, используйте обучающую часть для моделирования и вычислите точность предсказания, используя все образцы в вашем тестовом наборе. Повторите этот процесс, увеличивая k, и посмотрите, какой k лучше всего подходит для вашей модели.

from sklearn.cluster import KMeans
error_cost=[]
for i in range(3, 11):
  KM = KMeans(n_clusters=i, max_iter=100)
  try:
    KM.fit(df_normalized)
  except ValueError:
    print('Error on line', i)
  # calculate squared error for the clustered points
  error_cost.append(KM.inertia_ / 100)
# plot the K values against the squared error cost
plt.figure(figsize=(13,7))
plt.plot(range(3,11), error_cost, color='r', linewidth=3)
plt.xlabel('Number of k clusters')
plt.ylabel('Squared Error (Cost)')
plt.grid(color='white', linestyle='-', linewidth=2)
plt.show()

Использование визуализатора локтя для получения правильного значения K

import warnings; warnings.simplefilter('ignore')
from yellowbrick.cluster import KElbowVisualizer
# Instantiate the clustering model and visualizer
model = KMeans()
visualizer = KElbowVisualizer(model, k=(3,11))
visualizer.fit(X)
visualizer

K=5

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

Выполнение кластеризации K-средних для кластеризации окрестностей

# set number of clusters
kclusters = 5
# run k-means clustering
kmeans = KMeans(n_clusters=kclusters, random_state=0).fit(df_normalized)

Объединение данных кластера, то есть значений меток с каждым соседством в кадре данных df

df_clustered = pd.merge(df, df_normalized, left_index=True, right_index=True)
df_clustered.insert(0, 'Cluster Label', kmeans.labels_)

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

Каждая цветная точка представляет собой одну из групп окрестностей.

Folium используется для создания интерактивной карты с полученными данными.

# Matplotlib and associated plotting modules
import matplotlib.cm as cm
import matplotlib.colors as colors
# create map
map_clusters = folium.Map(location=[latitude,longitude], zoom_start=10)
# set color schemes for the clusters
x = np.arange(kclusters)
ys = [i + x + (i*x)**2 for i in range(kclusters)]
colors_array = cm.rainbow(np.linspace(0, 1, len(ys)))
rainbow = [colors.rgb2hex(i) for i in colors_array]
# add markers to the map
markers_colors = []
for lat, lon, poi, cluster in zip(df_clustered['Latitude'], df_clustered['Longitude'], df_clustered['Neighbourhood'], df_clustered['Cluster Label']):
    label = folium.Popup(str(poi) + ' Cluster ' + str(cluster), parse_html=True)
    folium.CircleMarker(
        [lat, lon],
        radius=5,
        popup=label,
        color=rainbow[cluster-1],
        fill=True,
        fill_color=rainbow[cluster-1],
        fill_opacity=0.3).add_to(map_clusters)
       
map_clusters

Изучение каждого кластера на предмет его составляющих

0-й кластер (красный)

df_clustered.loc[df_clustered['Cluster Label'] == 0]

1-й кластер (фиолетовый)

df_clustered.loc[df_clustered['Cluster Label'] == 1]

2-й кластер (синий)

df_clustered.loc[df_clustered['Cluster Label'] == 2]

3-й кластер (зеленый)

df_clustered.loc[df_clustered['Cluster Label'] == 3]

4-й кластер

df_clustered.loc[df_clustered['Cluster Label'] == 4]

Общий вид всех кластеров

df_clustered.groupby('Cluster Label').mean()

Мы видим, что 0-й кластер имеет:

  1. Наибольшая численность населения Южной Азии - ›Больше аудитории
  2. Наименьшее количество популярных заведений - ›Меньше конкуренции, а значит, больше продаж и прибыли.
  3. Самый высокий семейный доход после уплаты налогов - ›Люди, которые могут платить больше
  4. Средняя арендная плата второго наименее арендатора - ›Низкие затраты на приобретение земли, что снижает фиксированные эксплуатационные расходы.

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

Ссылка на мой репозиторий Github



Ссылка на полный отчет по проекту



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

Контактная информация:

Имя: Мохан Радж

Электронный адрес: [email protected]

Сайт: https://mohanr.site123.me

Этот проект является частью программы сертификации IBM Data Science Certification Program. Я искренне благодарю IBM, Coursera, всех преподавателей курсов и сокурсников за то, что они подарили мне такой замечательный опыт обучения.

Спасибо, хорошего дня!