R - преобразовать символьный вектор во фрейм данных - PullRequest
0 голосов
/ 05 июня 2018

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

У меня есть список символов, который выглядит следующим образом:

my_info <- c("Fruits",
             "North America",
             "Apples",
             "Michigan",
             "Europe",
             "Pomegranates",
             "Greece",
             "Oranges",
             "Italy",
             "Vegetables",
             "North America",
             "Potatoes",
             "Idaho",
             "Avocados",
             "California",
             "Europe",
             "Artichokes",
             "Italy",
             "Meats",
             "North America",
             "Beef",
             "Illinois")

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

снимок экрана консоли R

Типы продуктов и списки регионов всегда будут оставатьсяТо же самое, но продукты питания и их расположение могут быть изменены.

food_type <- c("Fruits","Vegetables","Meats")
region <- c("North America","Europe")

Я думал, что мне нужно использовать что-то вроде str_split, но использовать food_types и регионов в качестве своего рода разделителя?Но я не уверен, как поступить.Вектор символов имеет порядок.

Спасибо.

Ответы [ 3 ]

0 голосов
/ 05 июня 2018

У меня длинное решение, но оно должно работать, пока еда и местоположение всегда в одном и том же порядке.

Сначала создайте несколько фреймов данных с dplyr.

library(dplyr)

info <- data_frame(my_info = my_info) 
region <- data_frame(region_id = region, region = region)
food_type <- data_frame(food_type_id = food_type, food_type)

Затем создаем data.frame, который объединяет все это вместе и заполняет пропущенные значения tidyr и удаляет ненужные нам строки.Тогда Самый важный трюк - последний, создающий столбец cols на основе предположения, что порядок всегда одинаков!

library(tidyr)

df <- info %>% 
  left_join(food_type, by = c("my_info" = "food_type_id")) %>% 
  left_join(region, by = c("my_info" = "region_id")) %>% 
  fill(food_type) %>% 
  group_by(food_type) %>% 
  fill(region) %>% 
  filter(!is.na(region) & !(my_info == region)) %>% 
  ungroup %>% 
  mutate(cols = rep(c("food", "location"), group_size(.)/2 ))

Возвращает:

# A tibble: 14 x 4
   my_info      food_type  region        cols    
   <chr>        <chr>      <chr>         <chr>   
 1 Apples       Fruits     North America food    
 2 Michigan     Fruits     North America location
 3 Pomegranates Fruits     Europe        food    
 4 Greece       Fruits     Europe        location
 5 Oranges      Fruits     Europe        food    
 6 Italy        Fruits     Europe        location
 7 Beef         Meats      North America food    
 8 Illinois     Meats      North America location
 9 Potatoes     Vegetables North America food    
10 Idaho        Vegetables North America location
11 Avocados     Vegetables North America food    
12 California   Vegetables North America location
13 Artichokes   Vegetables Europe        food    
14 Italy        Vegetables Europe        location

Далее используйте tidyr для распределения столбцов в столбцы еды и местоположения.

df <- df %>%
  group_by(food_type, region, cols) %>%
  mutate(ind = row_number()) %>% 
  spread(cols, my_info) %>% 
  select(-ind)

# A tibble: 7 x 4
# Groups:   food_type, region [5]
  food_type  region        food         location  
  <chr>      <chr>         <chr>        <chr>     
1 Fruits     Europe        Pomegranates Greece    
2 Fruits     Europe        Oranges      Italy     
3 Fruits     North America Apples       Michigan  
4 Meats      North America Beef         Illinois  
5 Vegetables Europe        Artichokes   Italy     
6 Vegetables North America Potatoes     Idaho     
7 Vegetables North America Avocados     California

Все это можно сделать за один раз, просто удалите промежуточный этап создания data.frame.

0 голосов
/ 05 июня 2018

Вот три варианта.Все они используют na.locf0 из зоопарка и вектор cn, показанный только в первом.

1) Пусть cn будет вектором такой же длины, что и my_info, которыйопределяет номер столбца вывода, к которому принадлежит элемент my_info.Пусть cdef будет вектором определения выходного столбца 1: 4 с именами выходного столбца в качестве имен.Затем для каждого выходного столбца создайте вектор такой же длины, что и my_info, строки которого соответствуют этому столбцу, и NA для других элементов.Затем используйте na.locf0, чтобы заполнить значения NA и взять элементы, соответствующие столбцу 4.

library(zoo)

cn <- (my_info %in% food_type) + 2 * (my_info %in% region)
cn[cn == 0] <- 3:4

cdef <- c(food_type = 1, region = 2, food = 3, location = 4)

m <- sapply(cdef, function(i) na.locf0(ifelse(cn == i, my_info, NA))[cn == 4])

, что дает:

> m
     food_type    region          food           location    
[1,] "Fruits"     "North America" "Apples"       "Michigan"  
[2,] "Fruits"     "Europe"        "Pomegranates" "Greece"    
[3,] "Fruits"     "Europe"        "Oranges"      "Italy"     
[4,] "Vegetables" "North America" "Potatoes"     "Idaho"     
[5,] "Vegetables" "North America" "Avocados"     "California"
[6,] "Vegetables" "Europe"        "Artichokes"   "Italy"     
[7,] "Meats"      "North America" "Beef"         "Illinois"  

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

as.data.frame(mm, stringsAsFactors = FALSE)

2) В качестве альтернативы, мы можем создать m из cn, поместив my_info[i] в положение (i, cn [i]) nx 4-мм матрицы NA, используя na.locf для заполнения NA и взяв те строки, которые соответствуют столбцу 4.

n <- length(my_info)
m2 <- na.locf(replace(matrix(NA, n, 4), cbind(1:n, cn), my_info))[cn == 4, ]
colnames(m2) <- c("food_type", "region", "food", "location")

identical(m2, m) # test
## [1] TRUE

3) Третий вариант создания m из cn состоит в том, чтобы построить столбец матрицы за столбцом так:

m3 <- cbind( food_type = na.locf0(ifelse(cn == 1, my_info, NA))[cn == 3], 
        region = na.locf0(ifelse(cn == 2, my_info, NA))[cn == 3], 
        food = my_info[cn == 3], 
        location = my_info[cn == 4])

identical(m, m3) # test
## [1] TRUE
0 голосов
/ 05 июня 2018

Одним из решений может быть сначала преобразовать ваш my_info вектор в матрицу, используя ncol = 4.Это разделит ваш вектор на матрицу / фрейм данных.

Теперь вы можете применить правило для food_type и region и поменять местами любые food_type или region, присутствующие в других столбцах.

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

df <- as.data.frame(matrix(my_info, ncol = 4, byrow = TRUE))

names(df) <- c("Foodtype", "Region", "Food", "Location")

food_type <- c("Fruits","Vegetables","Meats")
region <- c("North America","Europe")

t(apply(df,1,function(x){
  for(i in seq_along(x)){
    #One can think of writing a swap function here. 
    if(x[i] %in% region ){
      temp = x[i]
      x[i] = x[2]
      x[2] = temp
    }
    #Swap any food_type wrongly placed in other column
    if(x[i] %in% food_type ){
      temp = x[i]
      x[i] = x[1]
      x[1] = temp
    }

  }
  x
}))


#       Foodtype       Region          Food         Location  
# [1,] "Fruits"       "North America" "Apples"     "Michigan"
# [2,] "Pomegranates" "Europe"        "Greece"     "Oranges" 
# [3,] "Vegetables"   "North America" "Italy"      "Potatoes"
# [4,] "Idaho"        "Europe"        "California" "Avocados"
# [5,] "Meats"        "North America" "Artichokes" "Italy"   
# [6,] "Fruits"       "North America" "Beef"       "Illinois"
# 
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...