R:将相同的行合并为一个(最好使用dplyr / tidyr)

时间:2015-09-08 19:32:35

标签: r dplyr tidyr

我有一个我似乎无法弄清楚的问题

我有一个像这样的数据框

df <- data.frame(c(rep_len("a",3), "b", "b"), c(rep_len(55, 3), 44, 44),c(rep_len(12, 3), 6, 6), c("na", 2, "na", 3, "na"), c("na", "na", 4, "na", 8), c(5, "na", "na", "na", "na"))
names(df) <- c("street", "latitude", "longitude", "A", "B", "C")

street latitude longitude     A   B   C
    a       55         12    na  na   5
    a       55         12     2  na  na
    a       55         12    na   4  na
    b       44          6     3  na  na
    b       44          6    na   8  na

我猜我正在寻找的方法是在'street','latitude','longitude'中折叠具有相同值的行,这样数据框就像这样

street latitude longitude     A   B   C
     a       55        12     2   4   5
     b       44         6     3   8  na

我最好的尝试是:

df %>%
  group_by(street) %>%
  summarise_each(funs(first))

但它不太正确。有什么想法吗?

3 个答案:

答案 0 :(得分:5)

我不明白为什么你有"na"个字符串 - R对于字符/因素有NA。无论如何,对于你的例子,也许你正在寻找这个:

library(data.table)
dt = as.data.table(df) # or convert in place using setDT

dt[, lapply(.SD, function(x) x[x != "na"]), by = .(street, latitude, longitude)]
#   street latitude longitude A B  C
#1:      a       55        12 2 4  5
#2:      b       44         6 3 8 NA

答案 1 :(得分:1)

要扩展@ mlt的评论,您可以使用tidyrreshape2的后继者)来重塑此内容。它看起来像

df %>%
  gather(type, value, -c(street, latitude, longitude)) %>%
  na.omit %>%
  spread(type, value)

这会将A / B / C列展开成行,省略NA字段,然后将它们展开。

如@eddi所述,您希望使用内置的NA值,而不是字符串&#34; na&#34;。我用了

dfs <- 'street latitude longitude     A   B   C
    a       55         12    NA  NA   5
    a       55         12     2  NA  NA
    a       55         12    NA   4  NA
    b       44          6     3  NA  NA
    b       44          6    NA   8  NA
'
df <- read.table(text=dfs, header=T)

答案 2 :(得分:1)

只要您使用标准dplyr代替NA并在创建"na"时指定stringsAsFactors=FALSE,此操作无需重新构建并仅使用df }:

df %>%
  group_by(street, latitude, longitude) %>%
  summarise_each(funs(ifelse(sum(is.na(.)==FALSE)==0, NA, .[which(is.na(.)==FALSE)])), matches("[A-Z]{1}"))

# Result
  street latitude longitude A B  C
1      a       55        12 2 4  5
2      b       44         6 3 8 NA

如果您更愿意坚持使用"na",那么这可行:

df %>%
  group_by(street, latitude, longitude) %>%
  summarise_each(funs(ifelse(sum(.!="na")==0, "na", .[which(.!="na")])), matches("[A-Z]{1}"))
相关问题