Объединить data.frames, суммируя значения одинаковых столбцов в R
У меня есть 3 кадра данных (строки: сайты, столбцы: название видов) обитания видов внутри участков. Номера строк идентичны, но номера столбцов отличаются, поскольку не все виды находятся во всех трех кадрах данных. Я хотел бы объединить их в один фрейм данных с обилием идентичных видов, суммированных. Например:
data.frame1
Sp1 Sp2 Sp3 Sp4
site1 1 2 3 1
site2 0 2 0 1
site3 1 1 1 1
data.frame2
Sp1 Sp2 Sp4
site1 0 1 2
site2 1 2 0
site3 1 1 1
data.frame3
Sp1 Sp2 Sp5 Sp6
site1 0 1 1 1
site2 1 1 1 5
site3 2 0 0 0
Я хочу иметь что-то вроде:
Sp1 Sp2 Sp3 Sp4 Sp5 Sp6
site1 1 4 3 3 1 1
site2 2 5 0 1 1 5
site3 4 2 1 2 0 0
Думаю, мне пришлось бы работать с слиянием, но до сих пор мои попытки не смогли получить то, что я хочу.
Любая помощь приветствуется.
Ответы
Ответ 1
Я бы использовал plyr
rbind.fill
следующим образом:
pp <- cbind(names=c(rownames(df1), rownames(df2), rownames(df3)),
rbind.fill(list(df1, df2, df3)))
# names Sp1 Sp2 Sp3 Sp4 Sp5 Sp6
# 1 site1 1 2 3 1 NA NA
# 2 site2 0 2 0 1 NA NA
# 3 site3 1 1 1 1 NA NA
# 4 site1 0 1 NA 2 NA NA
# 5 site2 1 2 NA 0 NA NA
# 6 site3 1 1 NA 1 NA NA
# 7 site1 0 1 NA NA 1 1
# 8 site2 1 1 NA NA 1 5
# 9 site3 2 0 NA NA 0 0
Затем агрегируйте с plyr's
ddply
следующим образом:
ddply(pp, .(names), function(x) colSums(x[,-1], na.rm = TRUE))
# names Sp1 Sp2 Sp3 Sp4 Sp5 Sp6
# 1 site1 1 4 3 3 1 1
# 2 site2 2 5 0 1 1 5
# 3 site3 4 2 1 2 0 0
Ответ 2
Другой альтернативой является использование melt/cast
из reshape2
. Вот простой пример:
df1 <- read.table(header=T, text="
Sp1 Sp2 Sp3 Sp4
site1 1 2 3 1
site2 0 2 0 1
site3 1 1 1 1")
df2 <- read.table(header=T, text="
Sp1 Sp2 Sp4
site1 0 1 2
site2 1 2 0
site3 1 1 1")
df3 <- read.table(header=T, text="
Sp1 Sp2 Sp5 Sp6
site1 0 1 1 1
site2 1 1 1 5
site3 2 0 0 0")
df1$site <- rownames(df1)
df2$site <- rownames(df2)
df3$site <- rownames(df3)
DF <- rbind(melt(df1,id="site"),melt(df2,id="site"),melt(df3,id="site"))
dcast(data=DF,formula=site ~ variable,fun.aggregate=sum)
site Sp1 Sp2 Sp3 Sp4 Sp5 Sp6
1 site1 1 4 3 3 1 1
2 site2 2 5 0 1 1 5
3 site3 4 2 1 2 0 0
Короче говоря, мы используем обозначение сайта как дополнительную переменную и конвертируем каждый формат данных в длинный формат, а затем объединяем их в единый блок данных. Последний содержит все значения в длинном формате. С помощью dcast
мы создаем требуемый вами фреймворк, сайты находятся в строках (слева от формулы), а переменные находятся в столбцах (справа от формулы). Функция суммы используется для переменных, для которых создаются несколько ячеек.
Конечно, код можно расширить до более общего случая с помощью циклов или * применять функции.
Ответ 3
Добавляя к имеющимся параметрам, вот еще две палки с базой R.
Первая опция: Широкая агрегация (вроде)
temp <- cbind(df1, df2, df3)
temp
# Sp1 Sp2 Sp3 Sp4 Sp1 Sp2 Sp4 Sp1 Sp2 Sp5 Sp6
# site1 1 2 3 1 0 1 2 0 1 1 1
# site2 0 2 0 1 1 2 0 1 1 1 5
# site3 1 1 1 1 1 1 1 2 0 0 0
sapply(unique(colnames(temp)),
function(x) rowSums(temp[, colnames(temp) == x, drop = FALSE]))
# Sp1 Sp2 Sp3 Sp4 Sp5 Sp6
# site1 1 4 3 3 1 1
# site2 2 5 0 1 1 5
# site3 4 2 1 2 0 0
Второй вариант: полуширинный до длинного в ширину
Концептуально это похоже на Максима. Ответ K: Получите данные в длинной форме, и это значительно облегчает манипулирование вещами:
> temp1 <- t(cbind(df1, df2, df3))
> # You'll get a warning in the next step
> # Safe to ignore though...
> temp2 <- data.frame(var = rownames(temp), stack(data.frame(temp)))
Warning message:
In data.row.names(row.names, rowsi, i) :
some row.names duplicated: 5,6,7,8,9 --> row.names NOT used
> xtabs(values ~ ind + var, temp2)
var
ind Sp1 Sp2 Sp3 Sp4 Sp5 Sp6
site1 1 4 3 3 1 1
site2 2 5 0 1 1 5
site3 4 2 1 2 0 0
Ответ 4
Альтернатива Аруну:
Создайте массив "шаблон" со всеми столбцами, которые вам понадобятся
Rgames> bbar<-data.frame('one'=rep(0,3),'two'=rep(0,3),'three'=rep(0,3))
Rgames> bbar
one two three
1 0 0 0
2 0 0 0
3 0 0 0
Затем, учитывая каждый из ваших фреймов данных, например
Rgames> bar1<-data.frame('one'=c(1,2,3),'two'=c(4,5,6))
Rgames> bar1
one two
1 1 4
2 2 5
3 3 6
Создайте расширенный фрейм данных:
Rgames> newbar1<-bbar
Rgames> for (jj in names(bar) ) newbar1[[jj]]<-bar[[jj]]
Rgames> newbar1
one two three
1 1 4 0
2 2 5 0
3 3 6 0
Затем суммируем все такие расширенные кадры данных. Неуклюжий, но простой.