Это эссе по науке о данных и машинному обучению по набору данных 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)