Это эссе по науке о данных и машинному обучению по набору данных Philadelphia Housing разделено на три части: В Части I (текущая страница) я проанализирую набор данных Philadelphia Housing и выделю некоторые из его особенностей. В следующем разделе (Часть-II) будет выполнена предварительная обработка данных и разработка функций, чтобы данные были совместимы с алгоритмами машинного обучения. Наконец, в Части III я рассмотрю некоторые алгоритмы машинного обучения, которые выполняют регрессионный анализ обработанных данных. На основе этих оценок следует выбрать лучший алгоритм (ы), чтобы сделать прогноз (ы) о ценах на жилье для рынка недвижимости Филадельфии. В приведенной ниже работе используется Python и его библиотеки (в основном Pandas и Scikit-Learn).

Студент, изучающий машинное обучение, имеющий дело с данными о жилье, возможно, уже знаком с данными о жилищном строительстве Бостона и данными о жилищном строительстве Эймса (Айова). Следовательно, вместо этих знакомых наборов данных я собираюсь работать над набором данных о жилищном строительстве Филадельфии для прогнозирования цен на жилье с использованием алгоритмов машинного обучения (Ridge, Lasso, Random Forests, XGBoost Regression и Keras-Tensor Flow Neural Networks). Насколько мне известно, для этого набора данных не проводится всесторонний анализ данных и машинное обучение, поэтому приведенный ниже анализ может быть полезен не только в качестве упражнения в изучении базового анализа данных и методов машинного обучения, но и для того, чтобы получить представление о них. рынок недвижимости Филадельфии - колыбели США!

Прежде чем приступить к работе, я особенно хотел бы поблагодарить доктора Андреаса Мюллера и Сару Гвидо - их книга Введение в машинное обучение с помощью Python помогла мне изучить и понять алгоритмы и методы машинного обучения Scikit-Learn, а также мою работу здесь это отражает. Я также многому научился на различных сайтах, посвященных науке о данных и машинному обучению. Особо хочу упомянуть четыре руководства по Kaggle: Расширенные методы регрессии. Эти учебные пособия с использованием Python и его библиотек связаны с машинным обучением данных о корпусах Эймса - я искренне надеюсь, что по крайней мере некоторые из читателей пройдут через эти четыре руководства.

(I). Анализ данных: понимание набора данных

Во-первых, давайте загрузим набор данных: данные Philadelphia Housing в формате значений, разделенных запятыми (csv), можно найти [здесь]. Примечание. Этот набор данных csv opa_properties_public представляет собой очень большой файл! Как только вы сохраните в нужной папке, мы готовы ...

Сначала импортируем базовые библиотеки:

import pandas as pd 
import numpy as np
import matplotlib.pyplot as plt # default library for making plots
import seaborn as sns # for making prettier plots!

(И-А). Введение в данные о жилищном строительстве Филадельфии:

(I-A-1). Импортируем (opa_properties_public) с моего компьютера и переименовываем его как «all_data»:

all_data = pd.read_csv(r’C:\Users\…\opa_properties_public.csv’)

Примечание. В приведенном выше примере замените три точки (…) на соответствующий адрес, по которому файл csv сохраняется на вашем компьютере.

(I-A-2). Давайте посмотрим на форму «all_data».

all_data.shape
# Out: (580652, 79)

Мы видим, что здесь 79 столбцов и 580 652 строки!

(I-A-3). Проверка функций (заголовков столбцов) all_data:

all_data.columns
Out: Index(['the_geom', 'lng', 'assessment_date', 'basements', 'beginning_point', 'book_and_page', 'building_code', 'building_code_description', 'category_code', 'category_code_description', 'census_tract', 'central_air', 'cross_reference', 'date_exterior_condition', 'depth',       'exempt_building', 'exempt_land', 'exterior_condition', fireplaces',       'frontage', 'fuel', 'garage_spaces', 'garage_type',       'general_construction', 'geographic_ward', 'homestead_exemption',       'house_extension', 'house_number', 'interior_condition', 'location',       'mailing_address_1', 'mailing_address_2', 'mailing_care_of',       'mailing_city_state', 'mailing_street', 'mailing_zip', 'market_value', 'market_value_date', 'number_of_bathrooms', 'the_geom_webmercator', 'number_of_rooms', 'number_stories', 'off_street_open', 'other_building', 'owner_1', 'owner_2', 'parcel_number', 'parcel_shape', 'quality_grade', 'recording_date', 'registry_number', 'sale_date', 'sale_price', 'separate_utilities', 'sewer', 'site_type', 'state_code', 'street_code', 'street_designation', 'street_direction', 'street_name',       'suffix', 'taxable_building', 'taxable_land', 'topography',       'total_area', 'total_livable_area', 'type_heater', 'unfinished', 'unit', 'utility', 'view_type', 'year_built', 'year_built_estimate', 'zip_code', 'zoning', 'objectid', 'lat', 'number_of_bedrooms'],      dtype='object')

(I-A-4). Теперь удалим определенные функции из «all_data».

drop_column_list = ['the_geom', 'assessment_date','beginning_point', 'book_and_page', 'category_code_description', 'cross_reference', 'house_number','location', 'mailing_address_1', 'mailing_address_2', 'mailing_care_of', 'mailing_city_state', 'mailing_street', 'market_value_date','the_geom_webmercator','other_building','owner_1', 'owner_2', 'parcel_number', 'recording_date', 'sale_date', 'registry_number', 'sale_price', 'unit', 'objectid','building_code', 'census_tract', 'date_exterior_condition', 'year_built_estimate', 'house_extension', 'mailing_zip', 'sewer', 'site_type','state_code',                    'street_designation', 'street_name', 'street_direction',       'geographic_ward']
data = all_data.drop(drop_column_list, axis = 1)

Есть несколько причин для отказа от перечисленных выше функций. Например, функции the_geom и the_geom_webmercator предназначены для карт - в настоящее время я не собираюсь делать данные интерактивными с картами (однако я буду делать это в будущем), поэтому я удаляю эти функции. . Функция category_code_description, как следует из названия, описывает функцию category_code, которую мы сохраняем. Отметим описание и удалим функцию описания. Затем функция mailing_zip. Это похоже на функцию, которую я сохраняю - «zip_code». Нет необходимости, чтобы две функции предоставляли одинаковую информацию. Другие функции, которые мы отбрасываем, либо недостаточно важны для обучения (например, «street_name» - одна и та же улица может проходить как через бедные, так и через богатые районы), либо просто используются для бухгалтерского учета (например, «registry_number»).

(I-A-5). Работа с целевой переменной (market_value):

(I-A-5-i). Удаление строк в «data», соответствующих элементам NaN (Not a Number) в «market_value» (поскольку я не думаю, что здесь уместно заменять «NaN» на median / mean, поскольку это наши целевые значения). У нас достаточно данных, поэтому удаление нескольких не должно повлиять на процесс обучения.

data = data.dropna(subset=[‘market_value’])

Проверка, есть ли еще какие-либо нулевые значения в столбце market_value:

data.market_value.isnull().any()
Out: False # good!

(I-A-5-ii). Поскольку значение market_value, равное «0», не имеет смысла с точки зрения цены дома, поэтому мы удалим и это:

data = data.drop(data[data.market_value == 0].index)

(I-A-6). Теперь, что касается остальных функций: во-первых, построение графиков функций с отсутствующими (NaN) данными, превышающими 100.

missing = data.isnull().sum()
missing = missing[missing >= 100]
missing.sort_values(inplace=True)
missing.plot.barh()
plt.title(“Features with missing values (nan’s) > 100”)
plt.ylabel(“Features”)
plt.xlabel(“Number of Missing values”)

Здесь мы видим, что функции «суффикс», «незавершенный», «полезность», «топливо», «качество_града» и «усадьба_exemption» имеют более половины своих значений как NaN. Позже мы сделаем выводы, какими могут быть эти значения NaN, и произведем значимые замены. Теперь давайте рассмотрим каждую функцию, разберемся с ней и разберемся с NaN. Мы также выполняем некоторую обрезку данных - везде, где это возможно.

(I-B). Понимание каждой функции в наборе данных:

(I-B-1). ‘Category_code’:

data.category_code.value_counts(dropna=False)
Out:
1 426976 # Code value: 1 = Single Family
6 44928  # Code value: 6 = Vacant Land
2 41538  # Code value: 2 = Multi Family
3 14489  # Code value: 3 = Mixed Use
4 13125  # Code value: 4 = Commercial
5 4286   # Code value: 5 = Industrial

В этом эссе мы имеем дело только с жилыми домами (чтобы ограничить объем обрабатываемых данных). Таким образом, удалив все строки, соответствующие категориям нежилых помещений:

# Deleting ‘Vacant Land’
data=data.drop(data[data.category_code == 6].index)
# Deleting ‘Commercial’
data=data.drop(data[data.category_code == 4].index)
# Deleting ‘Industrial
data=data.drop(data[data.category_code == 5].index)

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

fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(13, 4),    gridspec_kw={'wspace' : 0.3}) # 'wspace' gridspec_kw - for adjusting #                                distance between the two subplots
# Bar plot of number of houses for each category:
category_code_values = data.category_code.value_counts()
category_code_values.plot.bar(ax=ax1)
ax1.set_title('Number of houses with respect to category_code')
ax1.set_xlabel('category_code')
ax1.set_ylabel('Number of houses')
# Code snippet for Box plot: 'market_value' vs. 'category_code'
category_df = pd.concat([data['market_value'], 
                         data['category_code']], axis=1)
box_fig = sns.boxplot(x='category_code', y="market_value", data=category_df, ax=ax2)
box_fig.axis(ymin=0, ymax=800000)
ax2.set_title('market_value vs category_code')

Здесь мы видим, что большинство домов в Филадельфии - это дома для одной семьи (что верно почти для любого города). На графике «рыночное_значение» и «код_категории» мы наблюдаем следующее: (1) Медианная рыночная стоимость для категорий «многосемейный» и «смешанный» одинакова и также больше, чем медиана для «одноразового использования». -семейные дома. (2) Категория «смешанное использование» не симметрична, но имеет справедливый перекос, т. Е. Большинство наблюдений относятся к нижней границе медианного значения market_value. (3) категория домов «смешанного использования» имеет более высокие выбросы. Это говорит о том, что по крайней мере некоторые из домов «смешанного использования» могут быть довольно дорогими по сравнению с домами двух других категорий. Это может быть связано с тем, что дома "смешанного использования" могут также содержать коммерческую / офисную недвижимость, которая, как правило, стоит дороже. Примечание. В приведенном выше прямоугольном графике (а также в последующих) мы пренебрегаем крайними выбросами (то есть точками данных, которые выступают над верхней полосой максимального значения).

(I-B-2). 'глубина':

Признак «глубина» включает некоторые значения, равные «0». Поскольку глубина «0» для дома тоже не имеет смысла, я собираюсь удалить все строки из данных, соответствующие нулям в столбце глубины.

data = data.drop(data[data.depth = 0].index)

(I-B-3). ‘Lng’ (долгота):

Сначала мы заполняем NaN средним значением всех данных lng:

data["lng"] = data.lng.fillna(data.lng.mean())

Во-вторых, глядя на 5 строк столбца «lng»,

data.lng.value_counts(dropna=False).head(5)
Out: 
-75.142107    36
-75.141891    12
-75.138198    10
-75.138409    10
-75.149173    10

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

data.loc[:, "lng"] = data['lng'].abs()

Наконец, мы просматриваем гистограмму функции «lng»:

fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(13, 4), 
      gridspec_kw={'wspace' : 0.3})
# Histogram of longitude:
data.loc[:, "lng"] = data['lng'].abs()
data["lng"].plot(kind='hist', ax=ax1)
ax1.set_title("Histogram of Longitude")
ax1.set_xlabel("Longitude")
ax1.set_ylabel("Distribution")
# market_value vs longitude:
lng_df = pd.concat([modified_data['market_value'], modified_data['lng']], axis=1)
fig1 = lng_df.plot.scatter(x='lng', y='market_value', ax=ax2)
fig1.axis(ymin=0, ymax=150000000);
ax2.set_title('market_value vs lng')

Проделав аналогичный процесс для функции «широта», мы получим:

Сравнивая приведенные выше графики (рис. 3 и 4) с картой города Филадельфия, мы видим, что, как и следовало ожидать, самые дорогие дома расположены в районе Old City / Center City.

(I-B-4). 'почтовый индекс':

Давайте просканируем первые пять значений zip_code в соответствии с их количеством значений:

data.zip_code.value_counts(dropna=False).head()
Out: 
19150-0000    2125
19138-0000    1692
19120-0000    1621
19119-0000    1109
19142-0000    1010

Поскольку между двумя числами в «zip_code» есть дефис («-»), я уберу его. [Технически это не должно иметь большого значения на этапе машинного обучения, поскольку я собираюсь рассматривать функцию «почтовый индекс» как категориальную функцию, поэтому эта часть является необязательной.]

# Making 19150-0000 to 191500000, i.e. replacing '-'
data.loc[:, "zip_code"] = dat['zip_code'].str.replace('-', '')
# make sure there is no space between ''
data.loc[:, "zip_code"] = data['zip_code'].str.pad(width=9, side='right', fillchar='0').astype('int64')

Наконец, мы строим коробчатую диаграмму «market_value» и «zip_code». Здесь мы сосредотачиваемся на почтовых индексах, которые содержат более 50 домов, чтобы игнорировать редко заполненные почтовые индексы. Ниже приведен фрагмент кода для блочной диаграммы:

zip_code_df = pd.concat([data[‘market_value’], data[‘zip_code’]], axis=1)
# Selecting only the zip-codes that contain houses > 50
zip_code_select = zip_code_df.groupby(“zip_code”).filter(
 lambda x: len(x) > 50)
f, ax = plt.subplots(figsize=(18, 6))
ax.set_yscale(“log”) # making logarithmic y-axis (market_value)
fig = sns.boxplot(x=’zip_code’, y=”market_value”, data=zip_code_select, hue=’market_value’)
fig.set_xticklabels(fig.get_xticklabels(),rotation=60)

График показывает, что самый дорогой почтовый индекс - 19106–0000, который находится в районе «Холм Общества», который находится недалеко от центра города / района Старого города, что снова соответствует ожиданиям.

(И-Б-5). «Подвалы»:

Во-первых, давайте просканируем value_counts:

data.basements.value_counts(dropna=False)
Out:
NaN    169582  # [NOTE: REPLACING 'NaN' WITH 'L' (my definition)] 
D      122540  # D = Full – Unknown Finish
F       67708  # F = Partial - Semi-Finished 
H       63179  # H = Partial - Unknown Finish
C       21556  # C = Full - Unfinished
A       11310  # A = Full - Finished 
J        9160  # J = Unknown Size - Unfinished
0        7378  # 0 = No Basement [NOTE: REPLACING '0' WITH 'K']
E        4473  # E = Partial - Finished 
I        2422  # I = Unknown Size - Finished 
G        2010  # G = Partial - Unfinished
B        1173  # B = Full - Semi-Finished

В «подвальных» данных много NaN. Я заменю эти NaN на "L" (мое определение). Я также заменю '0' (без подвала) на 'K' (мое определение), так что это удобно во время преобразования dummy_variables - хотя этот шаг тоже можно пропустить, поскольку здесь '0' - это строка, которая будет правильно обрабатываться как категория. Давайте посмотрим на гистограмму и коробчатую диаграмму:

data.loc[:, "basements"] = data.loc[:, "basements"].fillna('L')
data.loc[:, "basements"] = data['basements'].replace('0', 'K')
# Bar plot of 'Number of houses' vs 'basements':
basement_values = data.basements.value_counts()
basement_values.plot.bar()
plt.title("Number of houses vs. 'basements'", fontsize=15)
plt.xlabel("Basement feature types", fontsize = 12)
plt.ylabel("Number of houses", fontsize = 12)
# Box plot 'basements' vs. 'market_value': [showing a brief code]
basements_df = pd.concat([data['market_value'], data['basements']], axis=1)
f, ax = plt.subplots(figsize=(5, 3))
fig = sns.boxplot(x='basements', y="market_value",data=basements_df)
fig.axis(ymin=0, ymax=700000)

Из графика «рыночная_ценка» и «подвалы» мы видим, что средняя цена дома типа А (полностью законченный подвал) немного выше, чем у домов с другими типами цокольной отделки. Кроме того, некоторые дома с готовыми подвалами могут стать довольно дорогими, поэтому готовый подвал является плюсом в рыночной оценке. Сравнивая два графика на рис. 6, мы можем сделать вывод, что тип L (NaN) может относиться в основном к недостроенным подвалам и что в большинстве домов в Филадельфии есть дома с в основном недостроенными подвалами.

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

(I-B-6). ‘Central_air’:

# Replacing '0' with 'N' (i.e. NO central_air)
data.loc[:, "central_air"] = data['central_air'].replace('0', 'N')
# Replacing the "NaNs" with 'N'
data.loc[:, "central_air"] = data['central_air'].fillna('N')
# Box plot 'central_air' vs. 'market_value': [showing a brief code]
ac_df=pd.concat([data['market_value'], data['central_air']], axis=1)
fig = sns.boxplot(x='central_air', y="market_value", data=ac_df)

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

(I-B-7). ‘External_condition’:

4,0 = Среднее значение (404 701)
3,0 = Выше среднего (24 664)
5,0 = Ниже среднего (21 279)
2,0 = Новое строительство / Восстановленное (20 974)
7,0 = Герметичный / структурно нарушенный (7192)
6,0 = свободный (3,404)
0,0 = неприменимо (271)

Как и ожидалось, более новые конструкции с внешними условиями выше среднего и выше имеют гораздо более высокую среднюю рыночную стоимость по сравнению с остальными. В то время как герметичные дома с наихудшими внешними условиями имеют одну из самых низких рыночных цен - выбросы здесь могут быть связаны исключительно с землей / местоположением. Признак «interior_condition» следует аналогичной тенденции и поэтому не отображается на графике. Примечание: числа в скобках (далее) означают количество домов, то есть количество домов для данного типа / категории.

(I-B-8). «Топливо» (отопительное топливо):

A = природный газ (5 934)
C = электрический (262)
B = мазут (109)
E = солнечный (12)
G = другой (476 171) )
H = Нет (3)

Примечание: здесь я заменил NaN на G (т.е. прочее).

(I-B-9). ‘Garage_type’:

0 = Нет (291 741)
A = Встроенный / Подвал (39 988)
F = Переоборудованный (24 359)
C = Отдельный гараж (18 833)
B = Пристроенный гараж (7 535)
S = Самостоятельная парковка (20)
T =
Дежурный ( 15)

Из Рис. 10 мы видим, что дома с пристроенным гаражом (тип B) имеют более высокую среднюю рыночную стоимость. Кроме того, наличие гаража увеличивает стоимость дома. Удивительно, но дома типа Т (гаражи с сопутствующей парковкой) не так уж и дороги! Я бы предположил, что гаражи с сопровождающей парковкой будут дороже (хотя с небольшой выборкой из 15 домов мы не можем здесь много обобщать).

(И-Б-10). «Общая_конструкция»:

Заменяя NaN на G и четырнадцать нулей на N (Нет), мы получаем коробчатую диаграмму:

A = Обычный кирпич (410669)
B = Кирпич и сайдинг (29161)
E = Камень (11022)
C = Каркас и сайдинг (9308)
F = Штукатурка / Цемент (7312)
G = Другой / Смешанный (7386)
H = Кирпич и штукатурка (4549)
J = Камень / штукатурка (1693)
I = Штукатурка и сайдинг (1130)
D = Каркас и черепица (247)

(I-B-11). ‘Homestead_exemption’:

# Replacing the "NaN's" with '0.0' (no homestead exemption)
data.loc[:, "homestead_exemption"] = data['homestead_exemption'].fillna(0.0)

(И-Б-12). ‘Parcel_shape’:

# Replacing the "NaN's" with 'F'
data.loc[:, "parcel_shape"] = data['parcel_shape'].fillna('F')
# Replacing (' ') with 'F' - as in the 'parcel_shape' column, there # are some empty cells -> so we fill them with 'F'
data.loc[:, "parcel_shape"] = data['parcel_shape'].replace(' ', 'F')

E = прямоугольный (448660)
A = кроме квадрата, прямоугольника или треугольника (29015)
B = изгибы, узкие участки, длинные подъездные пути (3915)
C = треугольник (711)
F = NaN (141)
D = Длинный и узкий (48)

(I-B-13). ‘Quality_grade’:

# Replacing the "NaN's" with '3.0' (As most of the houses in 
# Philadelphia are of Average quality - it's average!)
data.loc[:, "quality_grade"] = data['quality_grade'].fillna(3.0)

3,0 = средний (470615)
4,0 = выше среднего (11041)
6,0 = самый высокий (590)
5,0 = отличный (185)
2,0 = ниже среднего (45 )
1.0 = Низкое (14)

Рис. 13 довольно интересен. Можно сказать, что дома лучшего качества, как и ожидалось, обычно дороже. Однако некоторые дома очень низкого качества стоят не меньше, а то и дороже! Это может быть эффект местоположения - дом низкого качества в хорошем районе может быть столь же дорогим, как дом более высокого качества в бедном районе. Кажется, это соответствует старой пословице в сфере недвижимости: местоположение, местоположение, местоположение!

(И-Б-14). «Отдельные_утилиты» (только для 2–4 квартир):

D = Non - от 2 до 4 квартир (459960)
B = Часть отдельно (11014)
A = Центральная (обогреватель, бак для горячей воды, электричество, газ) (8394)
C = Все отдельно (кроме воды) (3123)

Ось Y - логарифмическая.

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

(И-Б-15). 'суффикс':

data.suffix.value_counts(dropna=False)
Out: 
NaN 481663 # [Replacing NaN’s with N — No suffix needed/provided]
2      386 # [Replacing 2 with H (half an address)]
R      382 # to indicate Rear in address
A       56 # to indicate Air Rights
L        4 # Leasehold

(И-Б-16). «Топография»:

F = Уровень улицы (443 811)
A = Уровень выше улицы (28 859)
E = Другое и NaN (9 315)
B = Уровень ниже улицы (232)
C = пойменная равнина (166)
D = скалистая (107)

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

(И-Б-17). «Type_heater» (тип нагревателя или системы отопления):

H = Не определено и NaNs (342804)
A = Горячий воздух (воздуховоды) (74373)
B = Горячая вода (радиаторы или плинтусы) (57643)
G = Излучение (4103 )
N = Нет (1898)
C = Плинтус с электроприводом (743)
E = Другое (581)
D = Внешний тепловой насос (346)

(I-B-18). «Незавершенный»:

data.unfinished.value_counts(dropna=False)
Out: 
NaN  480526 # [Replacing NaN’s with N (NOT Unfinished = Finished)]
U      1965 # Unfinished 

(И-Б-19). «Полезность» (относится к общей модернизации или реконструкции):

A = Нет и NaN (482035)
B = Модернизировано (294)
D = Модернизировано и реконструировано (117)
C = Модернизировано (относится к дизайну и плану этажа) (45 )

NaN может относиться к дому без модернизации / реконструкции или к полностью новому строительству.

На рис. 17 мы видим, что, как и ожидалось, модернизация и реконструкция старого дома увеличивает его рыночную стоимость.

(И-Б-20). ‘View_type’:

I = Обычный / Другой и NaNs (455726)
A = Городской / Горизонтальный (10437)
C = Парк / Зеленая зона (5068)
D = Коммерческий (3519)
N = Неприменимо (2857)
H = Промышленное (2778)
E = Здание / Ориентир (1951)
B = Проточная вода (155)

На рис. 18 мы видим, что дома рядом с парком / зеленью в целом более дорогие - как и ожидалось, как и в городе, зеленые насаждения менее распространены. Аналогичное обобщение можно сделать для дома возле проточного водоема. Однако, к моему удивлению, средняя стоимость домов вблизи промышленных зон тоже немного завышена!

(I-B-21). «Камины»:

Как видно из рис. 19, наличие камина в доме повышает его ценность!

(И-Б-22). ‘Number_stories’:

На рис. 20 мы узнаем, что по мере увеличения количества этажей с 2 ​​до 8 стоимость дома также увеличивается. Однако после этого мы видим некоторое выравнивание, с небольшими взлетами и падениями.

(И-Б-23). ‘Number_of_rooms’, ‘number_of_bedrooms’, ‘number_of_bathrooms’: Здесь мы сравниваем три участка друг с другом. Для этого мы делаем подзаголовки (код показан ниже).

# Box plot 'number_of_rooms' vs. 'market_value':
rooms_df = pd.concat([data['market_value'], 
                            data['number_of_rooms']], axis=1)
# Box plot 'number_of_bedrooms' vs. 'market_value':
bedrooms_df = pd.concat([data['market_value'], 
                            data['number_of_bedrooms']], axis=1)
# Box plot 'number_of_bathrooms' vs. 'market_value':
bathrooms_df = pd.concat([data['market_value'], 
                            data['number_of_bathrooms']], axis=1)
f, axes = plt.subplots(3, 1, figsize = (9.5, 10),                       gridspec_kw = {'hspace':.5}) 
# 'hspace' gridspec_kw for distance between the three subplots
sns.boxplot(x='number_of_rooms', y="market_value", 
data=rooms_df, ax=axes[0])
sns.boxplot(x='number_of_bedrooms', y="market_value", data=bedrooms_df, ax=axes[1])
sns.boxplot(x='number_of_bathrooms', y="market_value", data=bathrooms_df, ax=axes[2])
for ax in axes:
    ax.set_yscale("log")    
    ax.axis(xmin=-0.5, xmax=12.5)
    ax.axis(ymin=1000, ymax=3000000)
    
axes[0].set_title("logarithmic 'market_value' vs. 'number_of_rooms'", fontsize=15)
axes[1].set_title("logarithmic 'market_value' vs. 'number_of_bedrooms'", fontsize=15)
axes[2].set_title("logarithmic 'market_value' vs. 'number_of_bathrooms'", fontsize=15)