www.machinelearningmastery.ru

Машинное обучение, нейронные сети, искусственный интеллект
Header decor

Home

Учебник: Обработка и преобразование данных в R

Дата публикации May 30, 2017

Я думаю, что говорил это раньше ... но я люблю карты. Почти все используют их, что делает карты удивительным способом мгновенного обмена огромными объемами данных, не беспокоясь о том, что ваша аудитория будет подавлена.

Один из моих любимых инструментов для работы с пространственными данными - R. Помимо того, что он отлично подходит для обработки данных, его широкая пользовательская база означает, что есть множество пакетов, которые делают создание пользовательских карт супер быстрым и простым.

Это руководство предназначено для того, чтобы предоставить грубый, сквозной пример использования R для манипулирования и отображения данных. Цель состоит в том, чтобы создать карту, которая проиллюстрирует концентрацию собственности на жилые здания по всему району Бруклина, Нью-Йорк.

Мы будем использовать ряд наборов данных с портала OpenData в Нью-Йорке в дополнение к недавно выпущенномуКартографияпакет.

Чтобы пройти этот урок, вам понадобятся следующие инструменты:

Настройка среды и загрузка данных

1) Клонировать репозиторий GitHub

git clone https://github.com/spnichol/mapping_tutorial.git
cd mapping_tutorial

2) Создайте новый скрипт R и установите свой рабочий каталог

setwd("/home/you/mapping_tutorial")

3) Установите пакеты и загрузите первые два набора данных

install.packages(c("cartography", "rgdal", "sp"))

#ownership registrations
owners <- read.csv("data/owners.csv")

#building data
bldgs <- read.csv("data/bldg.csv")

Первый файлМногократные Жилищные Регистрации, реестр жилых зданий с тремя и более единицами. ВторойРегистрация Контакты, который содержит информацию, касающуюся владельцев зданий из предыдущего файла.

Изучение данных

Наша цель с этим проектом - получить представление о концентрации собственности на здания в Бруклине. Итак, естественное место для начала было бы с файлом собственности.

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

head(owners)

Ваш вывод должен выглядеть так:

Похоже, у нас есть две переменные ID:RegistrationContactIDа такжеRegistrationID, Первый относится к физическому лицу / компании, указанной в этом ряду, а второй относится к конкретной регистрации здания, которую сделал физическое / юридическое лицо.

У нас также естьCorporationNameколонка, которая может дать некоторое представление о том, кто чем владеет в Бруклине. Давайте использоватьaggregateфункция наRegistrationContactIDа такжеCorporationName,

owner_count <- aggregate(RegistrationID ~ RegistrationContactID, data=owners, FUN=length)
names(owner_count) <- c("RegistrationContactID", "Building_Count")
head(owner_count)
nrow(owner_count[owner_count$Building_Count > 2 ,])

Ваш вывод должен выглядеть так:

Теперь у нас есть один столбец с каждым уникальнымRegistrationContactIDи количество зданий, соответствующих ему. Помимо некоторых странно выглядящих идентификаторов (просто грязные данные), немного странно, что у нас только 274 владельца с более чем двумя зданиями. Давайте попробуем сCorporationName,

owner_count <- aggregate(org_agg <- aggregate(RegistrationID ~ CorporationName, data=owners, FUN=length)
names(org_agg) <- c("CorporationName", "Building_Count")
head(org_agg)
nrow(org_agg[org_agg$Building_Count > 2 ,])

Выход:

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

org_agg$CorporationName<- gsub("[^[:alnum:][:blank:]]", "", org_agg$CorporationName)
org_agg <- org_agg[org_agg$CorporationName !="" ,]
head(org_agg)
nrow(org_agg[org_agg$Building_Count > 2 ,])

Выход:

Мммм. Названия компаний выглядят немного лучше, но я все еще не уверен в количестве владельцев с более чем 2 зданиями. Этот набор данных включает в себя весь Нью-Йорк. В этом городе много зданий с большим количеством помещиков. Может ли быть так, что один и тот же арендодатель или управляющая компания регистрирует разные здания под разными именами / идентификаторами?

Что если мы посмотрим на их почтовый адрес? Давайте предположим, что домовладелец, регистрирующийся под разными именами, все еще захочет получать свою почту только в одном офисе. Мы можем создать новую переменную, объединив столбцы BusinessHouseNumber и BusinessStreetName и снова запустив нашу агрегацию.

owners$RealID <- paste(owners$BusinessHouseNumber, owners$BusinessStreetName, sep=" ")
real_agg <- aggregate(RegistrationID ~ RealID, data=owners, FUN=length)
names(real_agg) <- c("RealID", "Building_Count")
nrow(real_agg[real_agg$Building_Count > 2 ,])

Да, это имеет больше смысла. Мы не можем быть на 100% уверены, что некоторые из них на самом деле не являются разными арендодателями, которые имеют один и тот же почтовый адрес, но я думаю, что мы можем предположить, что это не так ради этого учебного пособия.

Тем не менее, есть проблема. Если вы еще не заметили, многие изRegistrationIDsвключить несколько контактов, каждый с разным значением дляТип, Прежде чем мы начнем их фильтровать, давайте разберемся с областью значений.

summary(owners$Type)

Вот что мы получаем:

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

Вместо этого, давайте просто удалим дубликатRegistrationIDи снова запустить нашaggregateфункция.

owners <- owners[! duplicated(owners$RegistrationID) ,]
real_agg <- aggregate(RegistrationID ~ RealID, data=owners, FUN=length)
names(real_agg) <- c("RealID", "Building_Count")
nrow(real_agg[real_agg$Building_Count > 2 ,])

Похоже, что после удаления дубликатов RegistrationID у нас есть около 5000 владельцев с более чем двумя зданиями.

Прежде чем мы перейдем к следующему шагу учебного пособия, давайте объединим столбец Building_Count с фреймом данных основных владельцев. Мы можем сделать это с помощью простогоmerge,

owners <- merge(x=owners, y=real_agg, by="RealID")

Объединение фреймов данных

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

1) Изучите переменные для структур данных зданий

head(bldgs)

Мой вывод выглядит так:

Хорошо, похоже, что оба набора данных разделяютRegistrationIDпеременная Это означает, что каждая запись в этом фрейме данных соответствует RegistrationID в фрейме данных владельцев. Мы можем использовать этот столбец в качестве нашего идентификатора дляmergeфункция.

2) Слияние по RegistrationID

bldg_counts<- merge(x=bldgs, y=owners, by="RegistrationID")

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

Изучение пространственных переменных

Теперь самое интересное. Нам нужно выяснить, какие ГИС-переменные мы можем использовать для агрегирования и построения этой информации. Давайте еще раз посмотрим на наш недавно объединенный фрейм данных.

bldg_counts<- merge(x=bldgs, y=owners, by="RegistrationID")

Выход:

Итак, похоже, у нас есть два варианта гео-переменных. Первым является адрес здания, который может быть получен путем объединенияНомер домаа такжеНазвание улицыколонны. Однако для того, чтобы отобразить эту информацию, нам нужно сначала геокодировать адреса. Слишком много работы.

У нас также естьблока такжеМногопеременные. Номера блоков в Нью-Йорке уникальны, это означает, что мы можем объединить число зданий в блоке с владельцами, владеющими более чем одним зданием. Город также предлагает файлы форм с многоугольниками на уровне блоков, что также позволяет нам отображать наши данные. Однако в Бруклине есть десятки тысяч блоков, в каждом из которых всего несколько зданий, так что это, вероятно, не будет слишком значимым.

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

1) Прочтите файл PLUTO CSV и изучите переменные

pluto_bk <- read.csv("data/pluto.csv")
names(pluto_bk)

Выход:

Видишь, что я говорил? Оставим только соответствующие столбцы.

2) Удалить ненужные столбцы

pluto_bk <- pluto_bk[, c(4, 5, 6, 58,71, 73, 74, 75)]

Мы остались со следующими столбцами:

Теперь у нас есть тонны вариантов. Я решил использовать трактат переписи, представленный в различных формах переменными CT2010 и Tract2010. Кажется, это хороший уровень агрегации, поскольку в Бруклине насчитывается около 750 переписных участков. Кроме того, Бюро переписей предлагает файлы форм на уровне тракта, что упрощает картографирование.

Нам нужно объединить эту информацию с нашим списком зданий, который мы создали ранее. К сожалению, PLUTO не имеет переменной RegistrationID, которую мы использовали ранее. Вместо этого они используют более распространенный BBL, что означает «Боро, Блок, Лот».

Наши данные зданий не имеютBBLпеременная, но мы можем сделать один, комбинируя столбцы города, здания и участка. Однако, во-первых, мы будем использоватьsprintfфункция, чтобы дополнить нашблока такжеМногопеременные.

Заполнение добавляет дополнительные нули к значениям, которые меньше определенного количества цифр. Это позволяет нашему окончательному BBL иметь длину в десять цифр, независимо от значения компонентов, из которых он состоит.

Мы также воспользуемся этой возможностью, чтобы поднастроить нашу структуру данных зданий, чтобы она включала только недвижимость в Бруклине. Мы делаем это, используяBoroIDиз3,

3) Создать переменную BBL в фрейме данных зданий

#subset dataframe for just Brooklyn 
bldg_counts <- bldg_counts [bldg_counts $BoroID == 3 ,]#create new columns with padded values
bldg_counts ["New_Block"] <- lapply(bldg_counts ["Block"], function(x) sprintf("%05d", x))
bldg_counts ["New_Lot"] <- lapply(bldg_counts ["Lot"], function(x) sprintf("%04d", x))#use paste function to combine everything into one variable
bldg_counts ["BBL"] <- as.numeric(paste(bldg_counts $BoroID, bldg_counts $New_Block, bldg_counts $New_Lot, sep=""))

Выглядит хорошо для меня. Давайте продолжим и объединим этот фрейм данных с данными PLUTO. Все, что мы хотим, - это участок переписи каждого здания, поэтому мы можем подгруппировать соответственно.

4) Объединить информацию о тракте с набором данных зданий

names(pluto_bk)
pluto_bk <- pluto_bk[, c(5, 2)]
nrow(bldg_counts)bldg_counts <- merge(x=bldg_counts, y=pluto_bk1, by="BBL")
nrow(bldg_counts)

Мы потеряли несколько сотен строк, которые по какой-либо причине отсутствовали в наборе данных PLUTO.

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

Если бы мы хотели быть более точными, мы могли бы создать уникальную переменную ID, комбинируяBBLс номером улицы для каждого здания.

5) Агрегировать по переписному тракту

#aggregate by census tract 
multiple <- bldg_counts[bldg_counts$Building_Count > 2 ,]
tract_counts <- aggregate(Building_Count ~ CT2010, data=multiple, FUN=length )
names(tract_counts)[1] <- "CTLabel"
nrow(tract_counts)
length(unique(pluto_bk$CT2010))

Первое, что бросается в глаза, это то, что мы потеряли кучу переписных участков. Объяснение простое. Хотя в районе насчитывается 761 участок, некоторые из них либо 1) очень маленькие, либо 2) почти полностью состоят из одноэтажных домов, которые не требуются для регистрации в городе. Поскольку в этих районах нет арендодателей с несколькими зданиями, они не будут отображаться в сводном списке.

Хорошо. У нас есть наш информационный фрейм с каждым участком переписи и количеством объектов недвижимости, принадлежащих землевладельцам с несколькими зданиями. Удивительно мало, но опять же, участки переписи не так уж и велики. Давайте карту!

картографирование

Первым шагом в любом картографическом проекте в R является чтение в нашем шейп-файле. Шейп-файл, который мы будем использовать для этого урока, получен из Департамента планирования города Нью-Йорка. В то время как Бюро переписей, как правило, является основным ресурсом для шейп-файлов, в версии Департамента планирования Нью-Йорка акватории уже обрезаны, поэтому они намного аккуратнее.

1) Загрузить шейп-файл

bk_shape <- readOGR(dsn = "shapefiles", layer = "nyct2010")
head([email protected])

Мы можем видеть, что этот шейп-файл на самом деле имеет 2166 различных участков переписи, поскольку он включает в себя все районы Мы также можем видеть, что он имеет данные, связанные с полигонами, что делает его пространством данных пространственных полигонов (SPDF). Эти данные включают в себя метку переписи, а также информацию о самих полигонах. Мы хотим связать наши данные с SPDF, но сначала нам нужно исправить некоторые вещи.

2) Подмножество SPDF
Подстановка SPDF в R нелепо проста. Вы можете сделать это как обычный фрейм данных.

#remember "3" is the BoroCode for Brooklyn 
bk_shape <- bk_shape[[email protected]$BoroCode == "3" ,]
head([email protected])

3) Объединить наши данные с SPDF

Добавление данных в полигоны в R также довольно просто. В этом случае нам просто нужно убедиться, что переменные идентификатора имеют одинаковые имена, и мы готовы к работе.

bk_shape <- merge(bk_shape, tract_counts, by="CTLabel")

Итак, вы видите, что мы теперь связали наши данные с SPDF, и мы готовы начать с карты.

4) Карта базовой карты
Вот где приходит пакет картографии. Чтобы начать построение нашей карты, нам нужно сначала нанести на карту «протяженность» карты (т. Е. Пространственный регион, который она будет занимать), а затем массу земли.

plot(bk_shape, border = NA, col = NA, bg = "#A6CAE0")
plot(bk_shape, col = "#E3DEBF", border=NA, add=TRUE)

Это должно выглядеть так:

5) Добавьте границы
Теперь мы собираемся добавить третий слой, который будет границами участков переписи.

plot(bk_shape, col = "grey60",border = "white", lwd=0.4, add=TRUE)

Теперь у вас должно быть это:

6) Выберите цветовую палитру
В пакете «Картография» есть много готовых цветовых палитр Я выбрал простой зеленый, но вы можете посмотреть на другихВотна странице 4. Я также решил использовать 8 разных цветов, хотя это всегда будет зависеть от распределения данных, которые вы используете.

cols <- carto.pal(pal1 = "green.pal" ,n1 = 8)

7) Добавьте слой хороплета
Этот пакет имеет множество различных функций для отображения данных, но мы собираемся придерживаться простой картограммы.

choroLayer(spdf = bk_shape, 
df = [email protected],
var = "Building_Count",
breaks = c(0, 10, 30, 50, 70, 90, 110, 150),
col = cols,
border = "grey40",
lwd = 0.5,
legend.pos = "left",
legend.title.txt = "Number of Buildings",
legend.values.rnd = 10,
add = TRUE)

Boooom. Это на самом деле оказалось довольно хорошим, так как оно очень близко соответствует тому, что я знаю, как это было анекдотически, если быть правдой после нескольких лет работы с помещиками в Бруклине. Темно-зеленые области также очень близко соответствуют районам города, которые испытали наибольшее облагораживание.

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

8) Добавить слой макета
Мы можем добавить немного метаданных на карту, создав слой макета.

layoutLayer(title = "Census Tracts by Building Ownership Concentration", 
author = "Pres Nichols",
sources = "Source: NYC OpenData",
scale = NULL,
col = NA,
coltitle = "black",
frame = FALSE,
bg = NA)

Вывод

Есть один важный аспект, который я не учел: что если в северных областях карты, предположительно с более концентрированной собственностью, просто будет больше зданий?

Если вы будете следовать этому руководству, я предоставлю вам возможность разобраться в этом и сообщить свои результаты!

Заметка:Те, кто не знаком с географией Бруклина, могут быть немного обеспокоены всеми белыми участками на карте. Это выглядит намного хуже, чем есть. Это связано с тем, что самые большие белые районы (Проспект-парк, Гринвудское кладбище и Рокуэйс) фактически не заселены. Если они все еще беспокоят вас, вы всегда можете придать необитаемым территориям другой цвет.

Оригинальная статья

Footer decor

© www.machinelearningmastery.ru | Ссылки на оригиналы и авторов сохранены. | map