Есть ли синтаксический сахар для определения фрейма данных в R - PullRequest
1 голос
/ 17 октября 2019

Я хочу перегруппировать штаты США по регионам, и поэтому мне нужно определить функцию отображения «Штат США» -> «Регион США», которая выполняется путем настройки соответствующего фрейма данных.

Основаэто упражнение (по-видимому, это карта «Содружества радиоактивных осадков»):

Commonwealth of the Fallout

Начинается с исходного списка в необработанном виде:

Alabama = "Gulf"
Arizona = "Four States"
Arkansas = "Texas"
California = "South West"
Colorado = "Four States"
Connecticut = "New England"
Delaware = "Columbia"

, что в конечном итоге приводит к следующему R-коду:

us_state <- c("Alabama","Arizona","Arkansas","California","Colorado","Connecticut",
"Delaware","District of Columbia","Florida","Georgia","Idaho","Illinois","Indiana",
"Iowa","Kansas","Kentucky","Louisiana","Maine","Maryland","Massachusetts","Michigan",
"Minnesota","Mississippi","Missouri","Montana","Nebraska","Nevada","New Hampshire",
"New Jersey","New Mexico","New York","North Carolina","North Dakota","Ohio","Oklahoma",
"Oregon","Pennsylvania","Rhode Island","South Carolina","South Dakota","Tennessee",
"Texas","Utah","Vermont","Virginia","Washington","West Virginia ","Wisconsin","Wyoming")

us_region <- c("Gulf","Four States","Texas","South West","Four States","New England",
"Columbia","Columbia","Gulf","Southeast","North West","Midwest","Midwest","Plains",
"Plains","East Central","Gulf","New England","Columbia","New England","Midwest",
"Midwest","Gulf","Plains","North","Plains","South West","New England","Eastern",
"Four States","Eastern","Southeast","North","East Central","Plains","North West",
"Eastern","New England","Southeast","North","East Central","Texas","Four States",
"New England","Columbia","North West","Eastern","Midwest","North")

us_state_to_region_map <- data.frame(us_state, us_region, stringsAsFactors=FALSE)

, который в высшей степени уродлив и не поддерживается, поскольку отображение состояния -> регион эффективно скрывается.

Я на самом деле написал программу на Perl для генерации вышеупомянутого из исходного списка.

В Perl можно написать что-то вроде:

#!/usr/bin/perl

$mapping = {
"Alabama"=> "Gulf",
"Arizona"=> "Four States",
"Arkansas"=> "Texas",
"California"=> "South West",
"Colorado"=> "Four States",
"Connecticut"=> "New England",
...etc...etc...
"West Virginia "=> "Eastern",
"Wisconsin"=> "Midwest",
"Wyoming"=> "North" };

, которую можно поддерживать, потому что одинможет проверять сопоставление построчно.

Должно быть что-то похожее на это совершенство Perl в R?

Ответы [ 4 ]

3 голосов
/ 17 октября 2019

Если us_region является именованным списком ...

us_region <- list(Alabama = "Gulf",
                  Arizona = "Four States",
                  Arkansas = "Texas",
                  California = "South West",
                  Colorado = "Four States",
                  Connecticut = "New England",
                  Delaware = "Columbia")

Тогда

us_state_to_region_map <- data.frame(us_state = names(us_region), 
                                     us_region = sapply(us_region, c),
                                     stringsAsFactors = FALSE)

и в качестве бонуса вы также получаете состояния в качестве имен строк .. .

us_state_to_region_map
               us_state   us_region
Alabama         Alabama        Gulf
Arizona         Arizona Four States
Arkansas       Arkansas       Texas
California   California  South West
Colorado       Colorado Four States
Connecticut Connecticut New England
Delaware       Delaware    Columbia
3 голосов
/ 17 октября 2019

Кажется, немного открытым для интерпретации того, что вы ищете.

Должен ли mapping быть элементом типа функции таким образом, чтобы вызов возвращал регион или наоборот (например, аналогично вызову функции mapping("alabama") => "Gulf")?

Я читаю вопрос, чтобы больше искать хранилище в стиле словаря, которое в R можно получить с эквивалентом list

ncountry <- 49
mapping <- as.list(c("Gulf","Four States",
...
,"Midwest","North"))
names(mapping) <- c("Alabama","Arizona",
...
,"Wisconsin","Wyoming")
mapping[["Pennsylvania"]]
[1] "Eastern"

Это может быть выполнено в одномзвоните

mapping <- list("Alabama" = "Gulf",  
                "Arizona" = "Four States", 
                 ..., 
                "Wisconsin" = "Midwest", 
                "Wyoming" = "North")

, что позволяет очень просто проверить, что отображение работает, как ожидалось. Однако это не очень хорошо конвертируется в 2 столбца data.frame, который мы затем получили бы, используя

mapping_df <- data.frame(region = unlist(mapping), state = names(mapping))

. Примечание «не красиво» просто означает, что as.data.frame не переводит входные данные в 2 столбца. output.

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

mapping_c <- c("Alabama" = "Gulf",  
                "Arizona" = "Four States", 
                 ..., 
                "Wisconsin" = "Midwest", 
                "Wyoming" = "North")

, который будет преобразован в data.frame почти таким же образом

mapping_df_c <- data.frame(region = mapping_c, state = names(mapping_c))

Обратите внимание, однако, на небольшую разницу в двух вариантах хранения. При ссылке на запись, которая существует с использованием либо одиночных скобок [, либо двойных скобок [[, работает нормально

#Works:
mapping_c["Pennsylvania"] == mapping["Pennsylvania"]
#output
Pennsylvania 
        TRUE
mapping_c[["Pennsylvania"]] == mapping[["Pennsylvania"]]
[1] TRUE

Но при ссылке на неизвестные записи они немного отличаются по поведению

#works sorta:
mapping_c["hello"] == mapping["hello"]
#output
$<NA>
NULL
#Does not work:
mapping_c[["hello"]] == mapping[["hello"]]

Ошибка в mapping_c [["hello"]]: индекс за пределами

Если вы конвертируете свой ввод в data.frame, это не проблема, но об этом стоит знатьиз этого вы получите ожидаемое поведение.

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

2 голосов
/ 17 октября 2019

Как говорит @ tim-biegeleisen, более целесообразно сохранить этот набор данных в базе данных, файле CSV или электронной таблице и открыть его в R (с помощью readxl::read_excel(), readr::read_csv(), ...).

Однако, если вы хотите написать это непосредственно в своем коде, вы можете использовать tibble:tribble(), который позволяет записывать строку данных по строкам:

library(tibble)
tribble(~ state, ~ region,
        "Alabama", "Gulf",
        "Arizona", "Four States",
(...)
        "Wisconsin", "Midwest", 
        "Wyoming", "North")
1 голос
/ 17 октября 2019

Одним из вариантов может быть создание фрейма данных в широком формате (ваш первоначальный список делает его очень простым, и это поддерживает очень очевидное отображение. На самом деле оно очень похоже на ваш код Perl), затем преобразуйте его вдлинный формат :

library(tidyr)

data.frame(
  Alabama = "Gulf",
  Arizona = "Four States",
  Arkansas = "Texas",
  California = "South West",
  Colorado = "Four States",
  Connecticut = "New England",
  Delaware = "Columbia",
  stringsAsFactors = FALSE
) %>%
  gather("us_state", "us_region") # transform to long format
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...