R-Преобразование столбца списков в разные столбцы, используя их значения в качестве имен (фиктивные)
У меня есть таблица, содержащая данные фильмов, и в последнем столбце у нее есть категории, к которым принадлежит фильм.
movieId title category
1 Toy Story (1995) Animation|Children|Comedy
2 Jumanji (1995) Adventure|Children|Fantasy
3 Grumpier Old Men (1995) Comedy|Romance
4 Waiting to Exhale (1995) Comedy|Drama
5 Father of the Bride Part II (1995) Comedy
6 Heat (1995) Action|Crime|Thriller
Я хочу создать один столбец для каждой категории и поставить 1, если он был записан в списке для этого фильма, и ноль, если нет.
Что-то вроде:
movieId title animation comedy drama
1 xx 1 0 1
2 xy 1 0 0
3 yy 1 1 0
До сих пор я только преобразовал строку в список с помощью:
f<-function(x) {strsplit(x, split='|', fixed=TRUE)}
movies2$m<-lapply(movies2$category, f)
Но я не знаю, как сделать все остальное.
Я думал о словарях Python. Но я не знаю, как это сделать в R.
Данные
df1 <- read.table(header = TRUE, stringsAsFactors = FALSE,
text = " movieId title category
1 'Toy Story (1995)' Animation|Children|Comedy
2 'Jumanji (1995)' Adventure|Children|Fantasy
3 'Grumpier Old Men (1995)' Comedy|Romance
4 'Waiting to Exhale (1995)' Comedy|Drama
5 'Father of the Bride Part II (1995)' Comedy
6 'Heat (1995)' Action|Crime|Thriller")
Ответы
Ответ 1
Мы можем использовать mtabulate
из qdapTools
после расщепления
library(qdapTools)
cbind(df1[-3],mtabulate(strsplit(df1$category, "[|]")))
# movieId title Action Adventure Animation Children Comedy Crime Drama Fantasy Romance Thriller
#1 1 Toy Story (1995) 0 0 1 1 1 0 0 0 0 0
#2 2 Jumanji (1995) 0 1 0 1 0 0 0 1 0 0
#3 3 Grumpier Old Men (1995) 0 0 0 0 1 0 0 0 1 0
#4 4 Waiting to Exhale (1995) 0 0 0 0 1 0 1 0 0 0
#5 5 Father of the Bride Part II (1995) 0 0 0 0 1 0 0 0 0 0
#6 6 Heat (1995) 1 0 0 0 0 1 0 0 0 1
Или используя base R
cbind(df1[-3], as.data.frame.matrix(table(stack(setNames(strsplit(df1$category,
"[|]"), df1$movieId))[2:1])))
Ответ 2
Здесь база R, которая использует strsplit()
для разделения значений столбца, затем grepl()
, чтобы соответствовать им в vapply()
. Трюк здесь состоит в том, чтобы использовать FUN.VALUE = integer(.)
в vapply()
, чтобы результат grepl()
был магически преобразован в целое число.
## split the 'category' column on '|'
s <- strsplit(df$category, "|", fixed = TRUE)
## run the unique sorted values through grepl(), getting integer result
newPart <- vapply(sort(unique(unlist(s))), grepl, integer(nrow(df)), df$category, fixed = TRUE)
## bind result to other columns
cbind(df[-3], newPart)
В результате получается следующий фрейм данных.
movieId title Action Adventure Animation Children Comedy Crime Drama Fantasy Romance Thriller
1 1 Toy Story (1995) 0 0 1 1 1 0 0 0 0 0
2 2 Jumanji (1995) 0 1 0 1 0 0 0 1 0 0
3 3 Grumpier Old Men (1995) 0 0 0 0 1 0 0 0 1 0
4 4 Waiting to Exhale (1995) 0 0 0 0 1 0 1 0 0 0
5 5 Father of the Bride Part II (1995) 0 0 0 0 1 0 0 0 0 0
6 6 Heat (1995) 1 0 0 0 0 1 0 0 0 1
Ответ 3
Экспериментальный подход:
library(dplyr)
library(tidyr)
library(reshape2)
library(stringr)
max.categories = max(str_count(df1$category, "\\|")) + 1
df1new = df1 %>% separate(category, into=letters[1:max.categories], sep="\\|") %>%
melt(c("movieId","title")) %>%
filter(!is.na(value)) %>%
dcast(movieId + title ~ value, fun.aggregate=length)
movieId title Action Adventure Animation Children Comedy Crime Drama Fantasy Romance Thriller
1 1 Toy Story (1995) 0 0 1 1 1 0 0 0 0 0
2 2 Jumanji (1995) 0 1 0 1 0 0 0 1 0 0
3 3 Grumpier Old Men (1995) 0 0 0 0 1 0 0 0 1 0
4 4 Waiting to Exhale (1995) 0 0 0 0 1 0 1 0 0 0
5 5 Father of the Bride Part II (1995) 0 0 0 0 1 0 0 0 0 0
6 6 Heat (1995) 1 0 0 0 0 1 0 0 0 1
max.categories
- это всего лишь способ программно гарантировать, что вектор into
не меньше, чем максимальное количество категорий для данного title
. Если вы уже знаете, что это значение никогда больше, чем, скажем, 5, то вы можете просто сделать, например, into=letters[1:5]
.