我有两个data.frames:
df1 (空,但具有特定的姓氏)
apple orange banana pear grape
0 0 0 0 0
DF2
fruit1 count1 fruit2 count2
apple 2 pear 1
grape 4 orange 2
banana 1 NA NA
这是我喜欢的输出:
apples oranges bananas pears grapes
2 0 0 1 0
0 2 0 0 4
0 0 1 0 0
我考虑过按照以下方式做的事情:
for f (in range(nrow(df2))){
for (i in range(ncol(df1))){
if(fruit1==columnName[i]){
df1[f,i]<-count1
ect...
但是,我正在处理一个相当大的数据集,这似乎不是正确的方法。
答案 0 :(得分:4)
data.table选项:
library(data.table)
setDT(df2)
# add row number
df2[, r := .I]
# "melt" common columns together
cols = c("fruit", "count")
m2 = melt(df2, measure=patterns(cols), value.name=cols)
# add unobserved fruits, if any
m2[, fruit := factor(fruit, levels = names(df1))]
# "cast" each fruit to its own column, ignoring NA rows
dcast(m2[!is.na(fruit)], r ~ fruit, fill = 0L, drop = FALSE)
r apple orange banana pear grape
1: 1 2 0 0 1 0
2: 2 0 2 0 0 4
3: 3 0 0 1 0 0
如果factor
中有一些不会出现在df1
中的额外关卡,则会df2
。如果您有一行fruit1
和fruit2
为空,那么您必须弄清楚如何扩展此方法。
答案 1 :(得分:2)
以下是使用dplyr
和tidyr
以及更少代码行完成此任务的另一种方法。但这不使用df1
。
library(dplyr)
library(tidyr)
# Create Data Frame
df2 <- data.frame(fruit1 = c("apple", "grape", "banana"),
count1 = c(2, 4, 1),
fruit2 = c("pear", "orange", NA),
count2 = c(1, 2, NA))
# Add row numbers
df2$row_num <- seq(1:3)
final <- df2 %>%
select(fruit1, count1, row_num) %>% #select the first group of fruit variables
rename(fruit2 = fruit1, count2 = count1) %>% # rename variables so they have the same name
bind_rows(df2[, c(3:5)]) %>% # combine with the second set of fruit variables
filter(!is.na(fruit2)) %>% # remove rows without a fruit
spread(fruit2, count2, fill = 0) %>% # spread data
select(-row_num) # remove the row numbers
答案 2 :(得分:1)
可能有一个更优雅的解决方案,但这是一种接近它的方法。我们的想法是将df2移动到长格式,然后将其连接到一个长格式data.frame,其中包含每行的所有可能的水果。将缺失值转换为零。然后将数据从长格式转换回宽。
# assemble df2
df2 <- structure(list(fruit1 = structure(c(1L, 3L, 2L),
.Label = c("apple", "banana", "grape"),
class = "factor"),
count1 = c(2L, 4L, 1L),
fruit2 = structure(c(2L, 1L, NA),
.Label = c("orange", "pear"),
class = "factor"),
count2 = c(1L, 2L, NA)),
.Names = c("fruit1", "count1", "fruit2", "count2"),
class = "data.frame", row.names = c(NA, -3L))
# add a column for row numbers
df2$r_number <- 1:nrow(df2)
# load libraries
library(tidyr)
library(dplyr)
# assemble a data.frame in long form by row numbers and fruits
fruit <- df2 %>%
select(starts_with("fruit"), r_number) %>%
gather(condition, fruits, starts_with("fruit")) %>%
mutate(condition = gsub("fruit", "key", condition)) %>%
filter(!is.na(fruits))
# assemble a data.frame in long form by row numbers and counts
count <- df2 %>%
select(starts_with("count"), r_number) %>%
gather(condition, counts, starts_with("count")) %>%
mutate(condition = gsub("count", "key", condition),
counts = ifelse(is.na(counts), 0, counts))
# join counts onto fruits
fruit %<>%
left_join(count, by = c("condition", "r_number")) %>%
mutate(fruits = paste0(fruits, "s")) %>%
select(-condition)
# create data.frame for all possible row numbers and fruits
all_possibles <- data.frame( r_number = rep(c(1:nrow(df2)), length(unique(fruit$fruits))),
fruits = unlist(lapply(unique(fruit$fruits), function(x) rep(x, nrow(df2)))))
# join actual fruits/counts onto all possible fruits and counts
# and shift data from long to wide
output <- all_possibles %>%
left_join(fruit, by = c("r_number", "fruits")) %>%
mutate(counts = ifelse(is.na(counts), 0, counts)) %>%
spread(fruits, counts) %>%
select(-r_number)
答案 3 :(得分:1)
考虑这个数据争论基础解决方案:
df1 <- data.frame(apple=0, orange=0, banana=0, pear=0, grape=0)
df2 <- read.table(text="apple 2 pear 1
grape 4 orange 2
banana 1 NA NA",
col.names = c("fruit1", "count1", "fruit2", "count2"))
# ITERATE BY ROW TAKING FRUIT AS HEADER AND COUNT AND CELLS
dfList <- lapply(1:nrow(df2), function(x) {
temp <- data.frame(df2[x, c('count1','count2')])
names(temp) <-c(as.character(df2[x,1]),
as.character(df2[x,3]))
return(temp)
})
# ADD/REMOVE FRUIT COLUMNS
temp <- lapply(dfList, function(y) {
for (x in names(df1)) {
if (!(x %in% names(y))) { y[[x]] <- 0 }
}
for (x in names(y)){
if (!(x %in% names(df1))) { y[[x]] <- NULL }
}
return(y)
})
finaldf <- do.call(rbind, temp)
names(finaldf) <- paste0(names(finaldf), 's')
finaldf <- finaldf[c('apples','oranges','bananas','pears','grapes')]
finaldf
# apples oranges bananas pears grapes
# 1 2 0 0 1 0
# 2 0 2 0 0 4
# 3 0 0 1 0 0