我有一个数据框,其中有一个列ID作为标识符,还有一些其他不同类型的列(因子和数字)。它看起来像这样
df <- data.frame(id = c(1, 1, 1, 1, 1, 2, 2, 3, 3, 4, 4, 4, 4),
abst = c(0, NA, 2, NA, NA, NA, 0, 0, NA, 2, NA, 3, 4),
farbe = as.factor(c("keine", NA, "keine", NA, NA, NA, "keine", "keine", NA, NA, NA, "rot", "rot")),
gier = c(0, NA, 5, NA, NA, NA, 0, 0, NA, 1, NA, 6, 2))
现在我想把重复的ID合并起来。数字列被定义为所有相同ID的平均值(不含NAs!)。因子列被合并成一个。NA可以省略。
最后的结果应该是这样的
dfRes <- data.frame(id = c(1, 2, 3, 4),
abst = c(1, 0, 0, 3),
farbe = as.factor(c("keine", "keine", "keine", "rot")),
gier = c(2.5, 0, 0, 3))
希望有一种方法可以快速计算,因为我有大约100万个观测值.先谢谢了!
编辑(补充)。"farbe "可能不是唯一的。在这种情况下,我认为我的数据最好的想法是有一个重复的行,但只有不同的 "farbe",所以有2个相同的ID和所有相同的,但不同的 "farbe "的值。这应该只是非常罕见的情况,但却是一个很好的补充。
在我的真实数据中,我有更多的数值和因子列。是否也可以创建一个解决方案,这样我就不必定义每一个列?
编辑:
刚刚看到你对非独特因素列和按类型选择列的编辑。这将是可行的,但我会想一个更干净的方法来做这件事,并向您汇报(我相信有一个简单的方法)。如果你想像原来的例子那样手动指定列,并且你有非唯一因子,只要使用 unlist()
与 unique()
与下面的方式相同。或者,您也可以考虑将所有的因子级别合并在一行,使用 paste()
与 collapse = "; "
或类似的东西。如果你想改变最终data.table的列顺序,可以使用 setcolorder()
在数据表上
setDT(df)
# For selecting columns later
num_cols <- sapply(df, is.numeric)
num_cols[names(num_cols) == "id"] <- FALSE
fac_cols <- sapply(df, is.factor)
df[, lapply(.SD, mean, na.rm = T), by = id, .SDcols = num_cols][
df[, lapply(.SD, function(i) unlist(unique(i[!is.na(i)]))), by = id, .SDcols = fac_cols], on = "id"]
id abst gier farbe
1: 1 1 2.5 keine
2: 2 0 0.0 keine
3: 3 0 0.0 keine
4: 4 3 3.0 rot2
5: 4 3 3.0 rot
它是如何工作的:它加入了数字列的摘要
df[, lapply(.SD, mean, na.rm = TRUE), by = id, .SDcols = num_cols]
与因素栏摘要
df[, lapply(.SD, function(i) unlist(unique(i[!is.na(i)]))), by = id, .SDcols = fac_cols]
编辑数据:
df <- data.frame(id = c(1, 1, 1, 1, 1, 2, 2, 3, 3, 4, 4, 4, 4),
abst = c(0, NA, 2, NA, NA, NA, 0, 0, NA, 2, NA, 3, 4),
farbe = as.factor(c("keine", NA, "keine", NA, NA, NA, "keine", "keine", NA, NA, "rot2", "rot", "rot")),
gier = c(0, NA, 5, NA, NA, NA, 0, 0, NA, 1, NA, 6, 2))
原有答复:
这里是许多人中的一个 data.table
解决方案。这将data.table按因子列排序,这样在汇总时就可以抓取最高值。我还把它转换回了一个纯粹的data.frame,但如果你不想这样做的话,就不必这样做。希望这能帮到你
另外,这是在假设 farbe
将是相同的每一个 id
library(data.table)
setDT(df)
df <- df[order(farbe), .(abst = mean(abst, na.rm = TRUE),
farbe = farbe[1],
gier = mean(gier, na.rm = TRUE)), by = id]
setDF(df)
df
id abst farbe gier
1 1 1 keine 2.5
2 2 0 keine 0.0
3 3 0 keine 0.0
4 4 3 rot 3.0
一个dplyr的解决方案。
library(dplyr)
df %>%
group_by(id) %>%
summarise(abst = mean(na.omit(abst)),
farbe = na.omit(farbe)[1],
gier = mean(na.omit(gier)))
#> # A tibble: 4 x 4
#> id abst farbe gier
#> <dbl> <dbl> <fct> <dbl>
#> 1 1 1 keine 2.5
#> 2 2 0 keine 0
#> 3 3 0 keine 0
#> 4 4 3 rot 3
创建于2020-05-14,由 重读包 (v0.3.0)
也是一个 data.table
解决办法。
library(data.table)
df <- data.table( # instead of data.frame
id = c(1, 1, 1, 1, 1, 2, 2, 3, 3, 4, 4, 4, 4),
abst = c(0, NA, 2, NA, NA, NA, 0, 0, NA, 2, NA, 3, 4),
farbe = as.factor(c("keine", NA, "keine", NA, NA, NA, "keine", "keine", NA, NA, NA, "rot", "rot")),
gier = c(0, NA, 5, NA, NA, NA, 0, 0, NA, 1, NA, 6, 2))
newdf <- df[,
.(abst=mean(abst,na.rm=T), # perform mean of abst removing NAs
farbe=na.omit(unique(farbe)), # assuming farbe is unique for each ID, extract the unique value after removing the NAs
gier=mean(gier,na.rm=T)), # perform mean of gier removing NAs
by=id] # for each ID
newdf
id abst farbe gier
1: 1 1 keine 2.5
2: 2 0 keine 0.0
3: 3 0 keine 0.0
4: 4 3 rot 3.0
补充解决方案
df %>%
group_by(id) %>%
fill(farbe, .direction = "updown") %>%
group_by(id, farbe) %>%
summarise_all(~ mean(., na.rm = T))