Плавный кадр данных переходит в один кадр без петель
У меня есть данные в формате корзины, как это:
V1 <- c('milk', 'beer', 'wrench', 'milk' )
V2 <- c('eggs', 'elbow grease', '', 'beer')
V3 <- c('water', '', '', '')
df <- data.frame(V1, V2, V3)
выход:
V1 V2 V3
1 milk eggs water
2 beer elbow grease
3 wrench
4 milk beer
То, что я хотел бы создать, - это фрейм данных в одном формате, например:
transaction product
1 1 milk
2 1 eggs
3 1 water
4 2 beer
5 2 elbow grease
6 3 wrench
7 4 milk
8 4 beer
На данный момент мне нужны данные в кадре данных, чтобы я мог фильтровать их перед тем, как переключиться на формат транзакций, который использует пакет apriori R.
Какой самый быстрый способ преобразовать этот фрейм данных из корзины в единый формат?
Прямо сейчас я использую цикл, который очень медленный.
dfSingle <- data.frame(product = character(),
transaction = integer())
for (row in 1:nrow(df)) {
# Create a list of products
productList <- unname(unlist(df[row, ]))
# Remove blank spaces
productList <- productList[!productList %in% ""]
# Convert to a dataframe
dfTemp <- as.data.frame(productList)
colnames(dfTemp) <- "product"
dfTemp$transaction <- row
# Bind to larger dataframe with previous rows
dfSingle <- rbind(dfSingle, dfTemp)
}
Я думал об использовании apply
чтобы применить эту функцию к каждой строке, но я не уверен, как связать несколько результирующих строк с результатами предыдущих строк.
5 ответов
Или подход data.table (однострочный)
Сначала расплавить получим транзакцию из имен строк: setDT(df)[, transaction := .I ]
Затем растопить, используя транзакцию в качестве id-столбца: melt( ... , id = "transaction" )
И, наконец, отбросьте пустые значения и верните первый и третий столбец: ...[!value == "", c(1,3) ]
melt( setDT(df)[, transaction := .I ], id = "transaction" )[!value == "", c(1,3) ]
# transaction value
# 1: 1 milk
# 2: 2 beer
# 3: 3 wrench
# 4: 4 milk
# 5: 1 eggs
# 6: 2 elbow grease
# 7: 4 beer
# 8: 1 water
Ты можешь использовать stack
, Хитрость заключается в том, чтобы транспонировать ваш фрейм данных, т.е.
df1 <- stack(as.data.frame(t(df), stringsAsFactors = FALSE))
df1[df1$values != '',]
values ind
#1 milk V1
#2 eggs V1
#3 water V1
#4 beer V2
#5 elbow grease V2
#7 wrench V3
#10 milk V4
#11 beer V4
ПРИМЕЧАНИЕ: простой rgex может извлечь только числа из ind
столбец, т.е.
df1$ind <- gsub('\\D+', '', df1$ind)
который даст,
values ind 1 milk 1 2 eggs 1 3 water 1 4 beer 2 5 elbow grease 2 7 wrench 3 10 milk 4 11 beer 4
После замены персонажа ""
с соответствующим форматом NA
, вы можете создать новую транзакцию столбца, а затем использовать reshape2::melt
:
df[df == ""] <- NA
df$transaction <- 1:nrow(df)
Затем:
melted_df <- na.omit(reshape2::melt(data=df, id.vars="transaction"))
который дает:
> melted_df
transaction variable value
1 1 V1 milk
2 2 V1 beer
3 3 V1 wrench
4 4 V1 milk
5 1 V2 eggs
6 2 V2 elbow grease
8 4 V2 beer
9 1 V3 water
Преимущество этой функции в том, что она даст вам столбец variable
который дает вам название столбцов предыдущего df
data.frame. Если это не относится к вам, удалите этот столбец, используя df$variable <- NULL
, Если вы также хотите отсортировать результат по возрастанию порядка транзакций:
out <- melted_df[order(melted_df$transaction), ]
что в итоге дает:
> out
transaction value
1 1 milk
5 1 eggs
9 1 water
2 2 beer
6 2 elbow grease
3 3 wrench
4 4 milk
8 4 beer
С tidyverse
ты можешь сделать:
df %>%
mutate_all(funs(ifelse(. == "", NA_character_, paste0(.)))) %>%
rowid_to_column(var = "transaction") %>%
gather(var, product, -transaction, na.rm = TRUE) %>%
select(-var) %>%
arrange(transaction)
transaction product
1 1 milk
2 1 eggs
3 1 water
4 2 beer
5 2 elbow grease
6 3 wrench
7 4 milk
8 4 beer
Во-первых, он заменяет пустые строки на NA_character_. Во-вторых, он создает переменную с идентификатором строки под названием "транзакция". В-третьих, он преобразует данные из широкого в длинный формат, а также удаляет строки с помощью NA_character_. Наконец, он упорядочивает данные в соответствии с "транзакцией".
Другая база R
альтернатива:
do.call(
rbind,
sapply(seq_along(df), function(i) cbind(transaction = i, product = df[[i]][nzchar(df[[i]])]))
)
transaction product
[1,] "1" "milk"
[2,] "1" "beer"
[3,] "1" "wrench"
[4,] "1" "milk"
[5,] "2" "eggs"
[6,] "2" "elbow grease"
[7,] "2" "beer"
[8,] "3" "water"