Использование функции и видоизменения для создания нового столбца в R - PullRequest
0 голосов
/ 14 октября 2018

У меня есть школьный проект, и я потратил более трех часов, пытаясь понять это.Первая переменная моего набора данных ("df") - "AREA".Я успешно отфильтровал его, поэтому единственными значениями являются названия штатов США.

Я ищу, чтобы создать новый столбец / переменную, которая называется «Регион».Он принимает штат, указанный в «ОБЛАСТИ», и возвращает одно из четырех обозначений региона переписи США.По-видимому, в R уже существует функция (state.region?), Но я не могу заставить ее работать, и я бы предпочел закодировать ее долгий путь.

Это то, что у меня есть после очистки данных и установки библиотек "dplyr", "tidyr" и "stringr":

#Create U.S. Census regions
regionconvert<-function(x)
{
  if(x %in% c("Texas","Oklahoma","Arkansas","Louisiana","Mississippi","Alabama","Georgia","Florida","Tennessee","Kentucky","West Virginia","Virginia","North Carolina","South Carolina", "Maryland","Delaware"))
    {return("South")}
  if(x %in% c("Maine","New Hampshire","Vermont","Massachusetts","Connecticut","Rhode Island","New York","New Jersey","Pennsylvannia"))
    {return("Northeast")}
  if(x %in% c("Ohio","Michigan","Illinois","Indiana","Wisconsin","Minnesota","Iowa","Missouri","North Dakota","South Dakota","Nebraska","Kansas"))
    {return("Midwest")}
  if(x %in% c("Alaska","Hawaii","Washington","Oregon","California","Nevada","Idaho","Utah","Arizona","New Mexico","Colorado","Wyoming","Montana"))
    {return("West")}
}
dfRegion=mutate(df,"Region"=regionconvert(df$AREA))

Я получаю следующую ошибку имой новый набор данных имеет «Юг» для каждой строки:

Предупреждающее сообщение: In if (x% в% c («Техас», «Оклахома», «Арканзас», «Луизиана», «Миссисипи»,: условие имеет длину> 1, и будет использоваться только первый элемент

Любая помощь, которую вы можете мне дать, чтобы это исправить, будет высоко ценится

Ответы [ 2 ]

0 голосов
/ 14 октября 2018

state.region - это фактор-вектор, а не функция.Он состоит из 50 элементов, упорядоченных по алфавиту значений названия государства.Чтобы объединить данные с набором данных из исходного сообщения, можно преобразовать их вместе с state.name в тиббл следующим образом.

library(tidyverse)
stateNames <- tibble(state = as.character(state.name),region = as.character(state.region))
head(stateNames)

... и первые несколько строк вывода:

> head(stateNames)
# A tibble: 6 x 2
  state      region
  <chr>      <chr> 
1 Alabama    South 
2 Alaska     West  
3 Arizona    West  
4 Arkansas   South 
5 California West  
6 Colorado   West  
>

Теперь информацию о состоянии можно объединить с переменной AREA, как описано в ответе r2evans.

0 голосов
/ 14 октября 2018

Фронт, не используйте df$ внутри ваш звонок на mutate.Одна из привлекательных сторон (и пунктов) большинства функций-глаголов dplyr заключается в том, что они работают без необходимости постоянно сообщать объекту набора данных.Таким образом, ваш вызов должен был выглядеть примерно так (хотя он все еще требует работы):

mutate(df, Region = regionconvert(AREA))

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

mtcars %>% group_by(cyl) %>% mutate(rnk = rank(mpg))
# # A tibble: 32 x 12
# # Groups:   cyl [3]
#      mpg   cyl  disp    hp  drat    wt  qsec    vs    am  gear  carb   rnk
#    <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
#  1  21       6  160    110  3.9   2.62  16.5     0     1     4     4   5.5
#  2  21       6  160    110  3.9   2.88  17.0     0     1     4     4   5.5
#  3  22.8     4  108     93  3.85  2.32  18.6     1     1     4     1   3.5
#  4  21.4     6  258    110  3.08  3.22  19.4     1     0     3     1   7  
#  5  18.7     8  360    175  3.15  3.44  17.0     0     0     3     2  13  
#  6  18.1     6  225    105  2.76  3.46  20.2     1     0     3     1   2  
#  7  14.3     8  360    245  3.21  3.57  15.8     0     0     3     4   4  
#  8  24.4     4  147.    62  3.69  3.19  20       1     0     4     2   5  
#  9  22.8     4  141.    95  3.92  3.15  22.9     1     0     4     2   3.5
# 10  19.2     6  168.   123  3.92  3.44  18.3     1     0     4     4   3  
# # ... with 22 more rows

, то rank вызывается три раза: первый раз с 11 значениями (cyl == 4), второй разс 7 значениями (cyl == 6), третий раз с 14 значениями (cyl == 8).Если бы вместо этого мы попытались вызвать:

mtcars %>% group_by(cyl) %>% mutate(rnk = rank(mtcars$mpg))

, то вызовы rank будут иметь 32 значения в каждом вызове.(Это не удалось бы, потому что mutate требует, чтобы каждый вызов функции возвращал либо 1 значение, либо то же количество значений, что и для ввода.)

Но если вы делаете что-то вроде

mtcars %>% group_by(cyl) %>% summarize(avg = mean(mpg))
mtcars %>% group_by(cyl) %>% summarize(avg = mean(mtcars$mpg))

, тогда первый даст средние значения для 1027 *, а второй сообщит одинаковое глобальное среднее для всех трех.


Хорошо, теперь на ваш вопрос:

Одинпроблема в том, что ваша функция ожидает, что x будет единичным значением (скалярно, технически в R это вектор длины 1).К сожалению, при вызове mutate передается вектор значений.Есть несколько способов справиться с этим, от наименее предпочтительного до большинства:

  1. Самый быстрый способ векторизации - это вернуть определенную область для каждого значения с помощью ifelse.Однако я предлагаю использовать dplyr::if_else здесь, поскольку он обеспечивает некоторые гарантии типа (а base::ifelse - нет).

    regionconvert2 <- function(x) {
      if_else(x %in% c("Texas","Oklahoma","Arkansas","Louisiana","Mississippi","Alabama","Georgia","Florida","Tennessee","Kentucky","West Virginia","Virginia","North Carolina","South Carolina", "Maryland","Delaware"),
              "South",
              if_else(x %in% c("Maine","New Hampshire","Vermont","Massachusetts","Connecticut","Rhode Island","New York","New Jersey","Pennsylvannia"),
                      "Northeast",
                      if_else(x %in% c("Ohio","Michigan","Illinois","Indiana","Wisconsin","Minnesota","Iowa","Missouri","North Dakota","South Dakota","Nebraska","Kansas"),
                              "Midwest",
                              if_else(x %in% c("Alaska","Hawaii","Washington","Oregon","California","Nevada","Idaho","Utah","Arizona","New Mexico","Colorado","Wyoming","Montana"),
                                      "West",
                                      NA_character_))))
    }
    
  2. Предварительно заполните полностью- NA вывод, затем замените отдельные значения, как мы их определяем:

    regionconvert3 <- function(x) {
      out <- x[NA]
      ind <- x %in% c("Texas","Oklahoma","Arkansas","Louisiana","Mississippi","Alabama","Georgia","Florida","Tennessee","Kentucky","West Virginia","Virginia","North Carolina","South Carolina", "Maryland","Delaware")
      out[ind] <- "South"
      ind <- x %in% c("Maine","New Hampshire","Vermont","Massachusetts","Connecticut","Rhode Island","New York","New Jersey","Pennsylvannia")
      out[ind] <- "Northeast"
      ind <- x %in% c("Ohio","Michigan","Illinois","Indiana","Wisconsin","Minnesota","Iowa","Missouri","North Dakota","South Dakota","Nebraska","Kansas")
      out[ind] <- "Midwest"
      ind <- x %in% c("Alaska","Hawaii","Washington","Oregon","California","Nevada","Idaho","Utah","Arizona","New Mexico","Colorado","Wyoming","Montana")
      out[ind] <- "West"
      return(out)
    }
    

    Мне это не очень нравится, честно говоря, так как он довольно жестко кодируется (и имеет повторяющийся код), поэтомуулучшенная версия выглядит примерно так:

    regionlist <- list(
      South = c("Texas","Oklahoma","Arkansas","Louisiana","Mississippi","Alabama","Georgia","Florida","Tennessee","Kentucky","West Virginia","Virginia","North Carolina","South Carolina", "Maryland","Delaware"),
      Northeast = c("Maine","New Hampshire","Vermont","Massachusetts","Connecticut","Rhode Island","New York","New Jersey","Pennsylvannia"),
      Midwest = c("Ohio","Michigan","Illinois","Indiana","Wisconsin","Minnesota","Iowa","Missouri","North Dakota","South Dakota","Nebraska","Kansas"),
      West = c("Alaska","Hawaii","Washington","Oregon","California","Nevada","Idaho","Utah","Arizona","New Mexico","Colorado","Wyoming","Montana")
    )
    regionconvert4 <- function(x, lookup) {
      out <- x[NA]
      for (nm in names(lookup)) {
        ind <- x %in% lookup[[nm]]
        out[ind] <- nm
      }
      return(out)
    }
    

    Цель этого второго варианта - заменить значение (вектор возможных значений) именем записей в списке.

  3. Небольшой разворот к предыдущей технике - обеспечить поиск сортов.Я изменю regionlist выше, и вместо имен, являющихся регионами, имена - это состояния.(Это может быть легко создано с помощью других средств.)

    statelist <- setNames(names(tibble::deframe(regiondf)),
                          tibble::deframe(regiondf))
    statelist[1:5]
    #       Texas    Oklahoma    Arkansas   Louisiana Mississippi 
    #     "South"     "South"     "South"     "South"     "South" 
    statelist[ c("Colorado","New Jersey") ]
    #    Colorado  New Jersey 
    #      "West" "Northeast" 
    

    Это устраняет необходимость в функции, ala statelist[AREA].

  4. Объединение / соединение.Это немного сложнее, но я думаю, что в долгосрочной перспективе это немного проще для сопровождения (например, вы можете вести список состояний / регионов в простой CSV или электронной таблице, что может значительно облегчить редактирование / изменение / расширение, так далее).Я сделаю этот новый кадр из объекта regionlist, но его можно легко создать напрямую или с помощью более привычных средств:

    regiondf <- tibble::enframe(regionlist, name="region", value="AREA") %>% tidyr::unnest()
    regiondf
    # # A tibble: 50 x 2
    #    region AREA       
    #    <chr>  <chr>      
    #  1 South  Texas      
    #  2 South  Oklahoma   
    #  3 South  Arkansas   
    #  4 South  Louisiana  
    #  5 South  Mississippi
    #  6 South  Alabama    
    #  7 South  Georgia    
    #  8 South  Florida    
    #  9 South  Tennessee  
    # 10 South  Kentucky   
    # # ... with 40 more rows
    

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

sampledata <- data_frame(AREA = c("Colorado", "California", "New Jersey", "Florida", "Guam"))

sampledata %>%
  mutate(
    r2 = regionconvert2(AREA),
    r3 = regionconvert3(AREA),
    r4 = regionconvert4(AREA, regionlist),
    r5 = statelist[AREA]
  ) %>%
  left_join(regiondf, by = "AREA")
# # A tibble: 5 x 6
#   AREA       r2        r3        r4        r5        region   
#   <chr>      <chr>     <chr>     <chr>     <chr>     <chr>    
# 1 Colorado   West      West      West      West      West     
# 2 California West      West      West      West      West     
# 3 New Jersey Northeast Northeast Northeast Northeast Northeast
# 4 Florida    South     South     South     South     South    
# 5 Guam       <NA>      <NA>      <NA>      <NA>      <NA>     

(Если вы хотите использовать четвертую технику «слияния / объединения», ни один из mutate не требуется.)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...