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

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

Я создал приведенный ниже сценарий, который использует библиотеку Python под названием sqlalchemy для импорта данных в базу данных Postgresql с именем lcn_db.

Как только данные попали в Postgresql, они были визуально проверены с помощью операторов SELECT:

--SELECT * FROM sold;
--SELECT * FROM census;
--SELECT * FROM tract_crosswalk;

Далее типы данных были изменены по мере необходимости.

--Change data types for sold
ALTER TABLE sold ALTER COLUMN id TYPE TEXT;
--Change data types for census
ALTER TABLE census ALTER COLUMN tract TYPE TEXT;
--Change data types for tract_crosswalk
ALTER TABLE tract_crosswalk ALTER COLUMN id TYPE TEXT;
ALTER TABLE tract_crosswalk ALTER COLUMN tract TYPE TEXT;

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

--Join tract_crosswalk table and census table
CREATE TABLE tract_cw_census AS
SELECT
 tract_crosswalk.id,
 tract_crosswalk.tract,
 census.population,
 census.median_income,
 census.pop_w_bach_degree,
FROM
 tract_crosswalk
LEFT JOIN census
 ON tract_crosswalk.tract = census.tract;

Приведенный ниже код объединяет таблицу sold и таблицу tract_cw_census, чтобы создать таблицу sold_census. Эта таблица содержит все данные, необходимые для моего анализа.

--Join sold and tract_cw_census table
CREATE TABLE sold_census AS
SELECT
 sold.id,
 sold.sold_price,
 sold.beds,
 sold.baths,
 sold.area,
 sold.latitude,
 sold.longitude,
 tract_cw_census.population,
 tract_cw_census.median_income,
 tract_cw_census.pop_w_bach_degree,
 tract_cw_census.tract
FROM
 sold
LEFT JOIN tract_cw_census
 ON sold.id = tract_cw_census.id;

Затем был создан новый столбец с именем dist_down_town. В этой колонке указано приблизительное расстояние от данного дома до центра Питтсбурга. Для расчета этого расстояния были установлены модули Cube и Earthdistance. Стандартный метод расчета расстояний между двумя точками на плоскости X,Y (d(P1,P2) = (x2 x1)2 + (y2 y1)2) не работает, если поверхность, на которой нанесены точки, является сферической. В этом случае вычисляется расстояние между двумя точками на объекте приблизительно сферической формы (Земля). Модуль earthdistance предоставляет простой способ сделать это без необходимости записывать всю математику в функции SQL. Это не идеально, но будет работать для целей этого проекта.

--Calulate distance from each property to approximate center of downtown
--Install needed modules
CREATE EXTENSION CUBE;
CREATE EXTENSION earthdistance;
ALTER TABLE sold_census ADD COLUMN dist_down_town double precision;
UPDATE sold_census SET dist_down_town = (point(longitude,latitude) <@> point(-96.6986,40.4418));

Остальная очистка данных и разработка функций были выполнены с использованием Python. Приведенный ниже скрипт используется для импорта данных из базы данных Postgresql в блокнот Jupyter.

import psycopg2
import pandas as pd
from sqlalchemy import create_engine
#Create engine
engine = create_engine('postgresql://postgres:*****@localhost:5432/lcn_db')
#Connect server
dbConnection = engine.connect()
#Import data from Postgres
df = pd.read_sql("""SELECT * FROM \"sold_census\"""", dbConnection);
pd.set_option('display.expand_frame_repr', False)
#Print dataframe head
df.head()

Затем я удалил дубликаты и записи с отсутствующими значениями:

df.drop_duplicates(subset=['id'],inplace=True)
df.dropna(inplace=True)

Запуск df.shape показывает, что осталось 5226 строк после удаления дубликатов и записей с отсутствующими значениями.

Я также создал отдельный набор данных с именем xg_df, который включает переменную тракта, представленную в виде фиктивных переменных:

xg_df=df
dummies = pd.get_dummies(xg_df.tract)
xg_df=xg_df.join(dummies)
xg_df.drop(columns=['tract'],inplace=True)
xg_df.dropna(inplace=True)
xg_df.reset_index(inplace=True)
xg_df_sold = pd.DataFrame(xg_df['sold_price'])
xg_df.drop(columns=['sold_price'],inplace=True)
xg_df=xg_df.join(xg_df_sold)
xg_df.drop(columns=['index'],inplace=True)
xg_df.head()

В следующей статье будут рассмотрены этапы EDA и анализа проекта.