В этом коде R ...

df1 <- c("a","b","a","b","b","c","b","c","c","d","c","d")
dim(df1) = c(4,3)
df1 <- as.data.frame(t(df1))

for (i in 1:nrow(df1)) {
  df1[i,"paste"] <- paste(df1[i,!names(df1) %in% c("paste")],collapse="")
}

... Ожидаю увидеть:

V1   V2   V3   V4   paste
a    b    a    b    abab
b    c    b    c    bcbc
c    d    c    d    cdcd

... но вместо этого вижу:

V1   V2   V3   V4   paste
a    b    a    b    1111
b    c    b    c    2222
c    d    c    d    3333

Это кажется тривиальным, и я не понимаю, что не так с кодом. Может ли кто-нибудь объяснить, как мой код производит данный результат? Кроме того, есть ли другие идеи о том, как получить простой результат, который я хочу? Спасибо.

r
0
johnjps111 6 Сен 2016 в 18:47

3 ответа

Лучший ответ

Причина в том, что df1[i,!names(df1) %in% c("paste")] возвращает фрейм данных. Вы можете удалить фрейм данных из списка, чтобы paste работал правильно:

for (i in 1:nrow(df1)) {
    df1[i,"paste"] <- paste(unlist(df1[i,!names(df1) %in% c("paste")]),collapse="")
#                           ^^^^^^
}

df1
#  V1 V2 V3 V4 paste
#1  a  b  a  b  abab
#2  b  c  b  c  bcbc
#3  c  d  c  d  cdcd

Вот как paste работает с фреймом данных, если df1 содержит факторную переменную:

paste(df1[1:4], collapse = "")
# [1] "1:31:31:31:3"

В качестве альтернативы это также должно сработать для вас:

df1$paste = do.call(paste0, df1[1:4])
1
Psidom 6 Сен 2016 в 16:05

Возможно, более читаемый код с использованием dplyr без цикла for:

df1 %>%
 mutate(paste = paste0(V1,V2,V3,V4))
1
Gio Circo 6 Сен 2016 в 15:56

Другой вариант - использовать unite(), удобную функцию для объединения нескольких столбцов в один, из tidyr

library(tidyr)
unite(df1, paste, V1:V4, sep = "", remove = FALSE)

Который дает:

#  paste V1 V2 V3 V4
#1  abab  a  b  a  b
#2  bcbc  b  c  b  c
#3  cdcd  c  d  c  d
2
Steven Beaupré 6 Сен 2016 в 16:29