#!/usr/bin/env python # coding: utf-8 # # #
Индивидуальный проект по анализу данных # ##
Предсказание разрешения на строительные работы в San Francisco #
Автор материала: Фатыхов Тимур @FatykhovTimur
# # ### 1. Описание набора данных и признаков # Этот набор данных содержит информацию обо всех типах строительных разрешений с 1 января 2013 года по 25 февраля 2018 (почти 200к записей). Это не обязательно должно быть разрешение на строительство нового здания, надо также получать одобрение на изменение фасада, этажности, количества составных частей здания. А также при проведении трубопроводов, электричества, изменении планировки. Если кто то загорелся желанием узнать поподробнее, то [вот ссылка](https://www.thespruce.com/what-is-a-building-permit-1398344) с более подробным описанием строительных разрешений. Вышесказанное означает, что какие то признаки в строках, ожидаемо, будут иметь значение **NaN**, так как если мы хотим построить здание, то его существующая этажность не то чтобы 0. Ее попросту нет, как и материалов из которых здание существует (ведь оно не существует - спасибо кэп). #

# Данные настоящие и обновляются каждую субботу, спасибо открытому порталу Сан-Франциско. #
# **А зачем это все?** - по [некоторым данным](https://www.trulia.com/blog/trends/elasticity-2016/) несоответсвие спроса и предложения на рынке недвижимости связано с задержками на разрешение реализации строительных проектов. Банальная догадка: население выросло, надо снести парочку старых низких домов и построить новые. Пока получим разрешение на снос, а потом отдельное на строительство, а потом еще на проведение канализации и трубопровода - население выростет еще больше. Как бы было хорошо иметь систему, которая сама бы определяла дать разрешение или нет. #
#
# Каждую запись можно рассматривать как заявку в городской департамент. То есть в ней присутствует дата подачи, дата исполнения строительных работ (если они исполнились в конечном итоге), адрес, информация о старом здании и о новом (например старое из дерева, 3 этажа, а хотим построить кирпичную 5-этажку). Но, как говорится лучше один разу увидеть, поэтому давайте лучше глянем поближе... # In[ ]: import pandas as pd import warnings import numpy as np from matplotlib import pyplot as plt import seaborn as sns get_ipython().run_line_magic('matplotlib', 'inline') warnings.filterwarnings('ignore') # [**Ссылка**](https://www.kaggle.com/aparnashastry/building-permit-applications-data/data) по которой можно найти данные # In[ ]: df = pd.read_csv('./data/Building_Permits.csv', sep=',') # In[ ]: df.info() # Параметров очень много, как и их значений. Разберемся по порядку. Без паники. Сначала посмотрим ближе на самый интересный из всех: # In[ ]: # текущее состояние заявки # это и будет наш целевой признак df['Current Status'].value_counts() # - complete - исполнено (дом построен, фасад покрашен, пожарная сигнализация установлена и тд) # - issued - разрешение выдано # - filed - заявка подана (на рассмотрении) # - withdrawm - заявка отозвана (сам заявитель забрал) # - canceled - отменена департаментом # - expired - истек срок # - approved - заявка утверждена # - reinstated - восстановлена в правах # - suspend - заморожена # - revoked - аннулирована # - plancheck - проверка плана (плана проведения трубопровода, например) # - disapproved - заявка не одобрена # - incomplete - проект не завершен # - appeal - апелляция/обращение # Глубоко вникать в определение этих терминов можно долго (и это, будем честны, требует знаний того, как устроена работа в подобных департаментах). Но видно что они разделены на две основных группы: заявка одобрена и не одобрена. # Ну а теперь время узнать, какие свойства можно будет использовать для предсказания судьб будущих заявок (**жирным** выделены наиболее интересные для изучения, то есть те, что, возможно, будут **сильнее всего влиять на целевой признак**): # - Permit Number - номер заявки # - Permit Type - тип заявления (в виде числа) # - **Permit Type Definition - пояснение предыдущего пунтка (соответствие описаний и чисел, рассмотрим чуть подробнее далее)** # - Permit Creation Date - дата, в которую было выдан вердикт # - Block - блок (адрес) # - Lot - еще одна составляющая адреса # - **Street Number - номер улицы** # - Street Number Suffix - суффикс номера улицы (есть не у всех) # - **Street Name - название улицы** # - Street Suffix - суффикс названия улицы # - Unit - блок здания (1, 2534, 1432) # - Unit Suffix - суффикс блока (A, B, 4C) # - **Description - причины подачи заявки, описание деталей (починка крыши, снос стен и тд)** # - Current Status - статус заявки на данный момент (подробнее только что познакомились выше) # - Current Status Date - день, в который заявка преобрела актуальный статус # - **Filed Date - день подачи заявки** # - **Issued Date - день публикования заявки (день когда ее рассмотрели)** # - Completed Date - день, когда заявка исполнена (стены покрашены, проводка проведена, в общем работа сделана) # - **First Construction Document Date - дата, на которую назначено строительство** # - **Structural Notification - соблюдение некоторых юридических правил (значение Y - yes или NaN)** # - **Number of Existing Stories - кол-во этажей в существующем здании** # - **Number of Proposed Stories - кол-во предложенных в заявке этажей** # - **Voluntary Soft-Story Retrofit - кол-во этажей, удовлетворяющее сейсмическим условиям** # - **Fire Only Permit - предоставление противопожарной защиты (значение Y - yes или NaN)** # - Permit Expiration Date - дата истечения срока разрешения на работы # - **Estimated Cost - первоначальная оценка стоимости проекта** # - **Revised Cost - пересмотренная оценка** # - **Existing Use - назначение (использование) здания (гостиница, ресторан, жилой дом и тд)** # - **Existing Units - кол-во составных частей объекта (один дом или кооператив из 30 домов, например)** # - **Proposed Use - предложенное в заявке использование** # - **Proposed Units - предложенное кол-во составных частей объекта** # - **Plansets - кол-во планов, показывающих основную задумку проекта** # - **TIDF Compliance - соответствие еще одному юридическому условию (значение Y - yes или NaN)** # - Existing Construction Type - тип конструкции на момент подачи заявки в виде числа # - **Existing Construction Type Description - описание предыдущего пункта (например, кирпич или дерево)** # - Proposed Construction Type - предложенный тип конструкции # - **Proposed Construction Type Description - описание предыдущего пунтка ** # - **Site Permit - разрешение на строительную площадку** # - Supervisor District - район, к которому принадлежит объект (значение от 1 до 11) # - **Neighborhoods - Analysis Boundaries - окрестности, к которым принадлежит объект (например, Linkoln Park, South Beach, Russian Hill...)** # - Zipcode - индекс # - Location - координаты (широта, долгота) # - Record ID - ID записи в базе департамента # ___ # Наконец, рассмотрим какие типы запросов (разрешений) поступают в департамент: # In[ ]: df['Permit Type Definition'].value_counts() # - otc alterations permit - *other-the-counter*, то есть внебиржевый, частный запрос (дядя Antony захотел провести электричество) # - additions alterations or repairs - дополнения или ремонт # - sign - erect - возведение постройки # - new construction wood frame - новая конструкция с деревянной рамой (буду честен, что именно это значит - загадка. Перевел и понял как смог) # - demolitions - снос # - wall or painted sign - изменение внешнего вида стен (реклама, покраска фасада) # - new construction - новое строительство # - grade or quarry or fill or excavate - другое (оценка, копка карьера с целью добычи, насыпь/заполнение ямы, создание ямы) # ### 2. Первичный анализ данных # Вернемся к целевому признаку *Current Status* и немного прорядим данные. Заявки, которые на момент работы с данными находятся в обработке, ничем не помогут нашей модели, которая будет определять: разрешать ли стройку или нет. Также, например, если заявитель отозвал свою заявку, то никакой информации о решении департамента мы не имеем. Следовательно, подобные записи можно удалить (помечены ниже красным). # - complete - исполнено (дом построен, фасад покрашен, пожарная сигнализация установлена и тд) # - issued - разрешение выдано # - filed - заявка подана *(т.к. на рассмотрении)* # - withdrawm - заявка отозвана *(сам заявитель забрал)* # - canceled - отменена департаментом # - expired - истек срок *(департамент не успел принять решение)* # - approved - заявка утверждена # - reinstated - восстановлена в правах # - suspend - заморожена # - revoked - аннулирована # - plancheck - проверка плана (плана проведения трубопровода, например) *(решение еще не принято)* # - disapproved - заявка не одобрена *(заявка неправильно оформлена)* # - incomplete - проект не завершен (но, зато, одобрен) # - appeal - апелляция/обращение *(в принципе не имеет отношения к задаче)* # In[ ]: df = df[(df['Current Status'] != 'filed') & (df['Current Status'] != 'withdrawn') & (df['Current Status'] != 'expired') & (df['Current Status'] != 'plancheck') & (df['Current Status'] != 'disapproved') & (df['Current Status'] != 'appeal') ] # Посмотрим на процентное соотношение классов между собой: # In[ ]: df['Current Status'].value_counts()/df.shape[0]*100 # Видно, что распределение классов крайне не равномерное. # Так как мы поставили перед собой задачу создать модель, которая принимает решение о выдаче разрешения на строительные работы, то **отобразим множество упомянутых выше классов на множество {0, 1}** где 0 - отказать в запросе, 1 - одобрить проект. #
# Определим следующие классы как отказ в выдаче разрешения: cancelled, suspend, revoked. #
# Определим следующие классы как одобрение проекта: complete, issued, approved, reinstated, incomplete. # In[ ]: df['Current Status'] = df['Current Status'].map({'cancelled': 0, 'suspend': 0, 'revoked': 0, 'complete': 1, 'issued': 1, 'approved': 1, 'reinstated': 1, 'incomplete': 1}) # In[ ]: df['Current Status'] = df['Current Status'].astype('int64') # In[ ]: print('Распределение классов в процентах:') df['Current Status'].value_counts() /df.shape[0] * 100 # ### 3. Первичный визуальный анализ данных # Ан нет... Пора спать, завтра важная пара с утра, а я с Новосибирска (+4 от Мск). Но можно же несколько баллов заработать за первые два пунтка все равно, так? :D #

# Если это дойдет до глаз читателей, то прошу прощения, за украденное время. Хорошего дня :)