У меня есть следующий фрейм данных

ID <- c(1,2,3,4,5,6)
Boat  <- c("Green, Blue", "Green", "Blue","Pink, Blue, Green","Blue","Blue, Green")
Car <- c("White","White","","","White","")
Train <-c("Grey","","Grey","Grey","","Grey")
df <-data.frame(ID,Boat,Car,Train)

Что дает таблицу ниже

ID      Boat              Car            Train
1   Green, Blue          White          Grey
2      Green             White   
3      Blue                             Grey
4   Pink, Blue, Green                   Grey
5   Blue                 White
6   Blue, Green                         Grey

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

ID    Vehicle     Color
1     Boat        Green
1     Boat        Blue
1     Car         White
1     Train       Grey
2     Boat        Green
2     Car         White
3     Boat        Blue
3     Train       Grey
4     Boat        Pink
4     Boat        Green
4     Boat        Blue
4     Train       Grey
5     Boat        Blue
5     Car         White
6     Boat        Green
6     Boat        Blue
6     Train       Grey
r
1
cms72 29 Июл 2020 в 19:17

7 ответов

Лучший ответ

Вот еще один вариант. Сначала мы pivot_longer, затем мы разбиваем столбец на «,», затем мы unnest_longer и отфильтровываем результаты без каких-либо цветов. В идеале вы могли бы использовать values_transform в pivot_longer, но я не мог заставить это работать.

library(tidyverse)

df %>%
  pivot_longer(cols = -ID, names_to = "Vehicle",  values_to = "Color") %>%
  mutate(Color = str_split(Color, ",")) %>%
  unnest_longer(Color) %>%
  filter(Color != "")
#> # A tibble: 17 x 3
#>       ID Vehicle Color   
#>    <dbl> <chr>   <chr>   
#>  1     1 Boat    "Green" 
#>  2     1 Boat    " Blue" 
#>  3     1 Car     "White" 
#>  4     1 Train   "Grey"  
#>  5     2 Boat    "Green" 
#>  6     2 Car     "White" 
#>  7     3 Boat    "Blue"  
#>  8     3 Train   "Grey"  
#>  9     4 Boat    "Pink"  
#> 10     4 Boat    " Blue" 
#> 11     4 Boat    " Green"
#> 12     4 Train   "Grey"  
#> 13     5 Boat    "Blue"  
#> 14     5 Car     "White" 
#> 15     6 Boat    "Blue"  
#> 16     6 Boat    " Green"
#> 17     6 Train   "Grey"

Создано в 2020-07-29 с помощью пакетаprex (v0.3.0)

1
AndS. 29 Июл 2020 в 17:17

Вероятно, самый простой способ добиться этого - это сочетание pivot_longer и separate_rows из :

df %>% 
  pivot_longer(cols = -ID, names_to = "Vehicle", values_to = "Color") %>% 
  separate_rows(Color) %>% 
  filter(Color != "")

Результат:

# A tibble: 17 x 3
      ID Vehicle Color
   <dbl> <chr>   <chr>
 1     1 Boat    Green
 2     1 Boat    Blue 
 3     1 Car     White
 4     1 Train   Grey 
 5     2 Boat    Green
 6     2 Car     White
 7     3 Boat    Blue 
 8     3 Train   Grey 
 9     4 Boat    Pink 
10     4 Boat    Blue 
11     4 Boat    Green
12     4 Train   Grey 
13     5 Boat    Blue 
14     5 Car     White
15     6 Boat    Blue 
16     6 Boat    Green
17     6 Train   Grey 
1
h3rm4n 30 Июл 2020 в 09:51

Используйте функцию «стек».

Это переместит заголовки вашего столбца в столбец. Затем вы можете переименовать новые столбцы как обычно.

df_new <- stack(df)

Больше информации: http://www.datasciencemadesimple.com/stack-and-unstack -функции -в- г /

1
tomanizer 29 Июл 2020 в 16:24

С data.table вы можете сделать что-то вроде:

library(data.table)
melt(as.data.table(df), 1)[, list(trimws(unlist(strsplit(value, ",")))), .(ID, variable)][order(ID)]
#     ID variable    V1
#  1:  1     Boat Green
#  2:  1     Boat  Blue
#  3:  1      Car White
#  4:  1    Train  Grey
#  5:  2     Boat Green
#  6:  2      Car White
#  7:  3     Boat  Blue
#  8:  3    Train  Grey
#  9:  4     Boat  Pink
# 10:  4     Boat  Blue
# 11:  4     Boat Green
# 12:  4    Train  Grey
# 13:  5     Boat  Blue
# 14:  5      Car White
# 15:  6     Boat  Blue
# 16:  6     Boat Green
# 17:  6    Train  Grey

Использование cSplit из моего пакета "splitstackshape" делает код немного короче с тем же результатом:

library(splitstackshape)
cSplit(melt(as.data.table(df), 1), "value", ",", "long")[order(ID)]
#     ID variable value
#  1:  1     Boat Green
#  2:  1     Boat  Blue
#  3:  1      Car White
#  4:  1    Train  Grey
#  5:  2     Boat Green
# ... <<SNIP>> ...
# 14:  5      Car White
# 15:  6     Boat  Blue
# 16:  6     Boat Green
# 17:  6    Train  Grey
1
A5C1D2H2I1M1N2O1R2T1 30 Июл 2020 в 06:10
ID <- c(1,2,3,4,5,6)
Boat  <- c("Green, Blue", "Green", "Blue","Pink, Blue, Green","Blue","Blue, Green")
Car <- c("White","White","","","White","")
Train <-c("Grey","","Grey","Grey","","Grey")
df <-data.frame(ID,Boat,Car,Train) %>% 
   separate(Boat, into =paste0("Boat", 1:3), sep = ', ')

df2 <- df %>% 
  pivot_longer(cols = -ID, 
               names_to = 'Vehicle', 
               values_to = 'Color'
    ) %>% 
  filter(!is.na(Color)) %>%
mutate(Vehicle = str_remove(Vehicle,"[\\d-]"))

enter image description here

1
Susan Switzer 29 Июл 2020 в 16:43

Вы также можете использовать pivot_longer из tidyverse. Подробнее о повороте можно прочитать в этой виньетке.

ID <- c(1,2,3,4,5,6)
Boat  <- c("Green, Blue", "Green", "Blue","Pink, Blue, Green","Blue","Blue, Green")
Car <- c("White","White","","","White","")
Train <-c("Grey","","Grey","Grey","","Grey")
df <-data.frame(ID,Boat,Car,Train)


library(dplyr)
library(tidyr)

df %>% 
  pivot_longer(cols = c(Boat, Car, Train),
               names_to = "Vehicle", 
               values_to = "Color"
  )
#> # A tibble: 18 x 3
#>       ID Vehicle Color              
#>    <dbl> <chr>   <chr>              
#>  1     1 Boat    "Green, Blue"      
#>  2     1 Car     "White"            
#>  3     1 Train   "Grey"             
#>  4     2 Boat    "Green"            
#>  5     2 Car     "White"            
#>  6     2 Train   ""                 
#>  7     3 Boat    "Blue"             
#>  8     3 Car     ""                 
#>  9     3 Train   "Grey"             
#> 10     4 Boat    "Pink, Blue, Green"
#> 11     4 Car     ""                 
#> 12     4 Train   "Grey"             
#> 13     5 Boat    "Blue"             
#> 14     5 Car     "White"            
#> 15     5 Train   ""                 
#> 16     6 Boat    "Blue, Green"      
#> 17     6 Car     ""                 
#> 18     6 Train   "Grey"

Создано в 2020-07-29 с помощью пакетаprex (v0.3.0)

Я бы также предложил использовать NA_character_ вместо пустой строки.

1
maia-sh 29 Июл 2020 в 16:32

Вот отличное решение:

library(tidyr)
library(dplyr)

separate(df, Boat, into = paste0("Boat", 1:3), sep = ", ", fill = "left") %>%
  pivot_longer(-ID) %>%
  filter(!is.na(value) & nzchar(value)) %>%
  transmute(ID, Vehicle = gsub("\\d", "", name), Color = value)
#> # A tibble: 17 x 3
#>       ID Vehicle Color
#>    <dbl> <chr>   <chr>
#>  1     1 Boat    Green
#>  2     1 Boat    Blue 
#>  3     1 Car     White
#>  4     1 Train   Grey 
#>  5     2 Boat    Green
#>  6     2 Car     White
#>  7     3 Boat    Blue 
#>  8     3 Train   Grey 
#>  9     4 Boat    Pink 
#> 10     4 Boat    Blue 
#> 11     4 Boat    Green
#> 12     4 Train   Grey 
#> 13     5 Boat    Blue 
#> 14     5 Car     White
#> 15     6 Boat    Blue 
#> 16     6 Boat    Green
#> 17     6 Train   Grey

Создано в 2020-07-29 с помощью пакетаprex (v0.3.0)

1
Allan Cameron 29 Июл 2020 в 16:29
63158035