在R中删除重复行并计算数据框中的平均值。

3

我提供一个我正在处理的大型数据框的小例子,它有超过1,000列和200行。我想要将每个重复的行每列变成一个单独的行,而且同时对第一列相关的每个值取平均值(需要取平均的列是第6-8列等)。


Col1    Col2    Col3    Col4    Col5    Col6        Col7        Col8        Col9        Col10
A-001   7       40      1       J       3.985645    4.231623    2.36987     9.36545852  8.369663
A-001   7       40      1       J       1.458798    7.652123    1.236985    4.236987    1.22556633
B-002   8       50      0       K       5.00212     8.369562    7.4569852   5.36692     4.6632121
B-002   8       50      0       K       9.02336     1.2120145   3.0014588   8.214569    5.2223698
C-003   10      60      1       L       1.451203    5.321455    8.25963     2.03369878  4.3336988
C-003   10      60      1       L       1.65653     2.369898    8.2136999   7.21458777  5.3366
D-004   3       70      0       M       5.323211    1.147852    7.20014     5.36989     2.36555
D-004   3       70      0       M       4.36969     5.231478    4.23698     3.645478    9.214563
E-005   4       80      1       N       8.123256    9.2356478   5.3696      4.698889    7.366695
E-005   4       80      1       N       7.9632145   0.004555    1.24789     7.3696969   1.23655

预期输出:

col 1   col 2   col 3   col 4   col 5     col 6
A-001       7      40       1       J   2.49282
B-002       8      50       0       K   7.01274
C-003      10      60       1       L   1.55387
D-004       3      70       0       M   4.84645
E-005       4      80       1       N   8.04324

抱歉未按正确格式呈现,提前道歉。预先感谢任何提供帮助的人。
dd <- structure(list(col1 = structure(c(1L, 1L, 2L, 2L, 3L, 3L, 4L, 
4L, 5L, 5L), .Label = c("A-001", "B-002", "C-003", "D-004", "E-005"
), class = "factor"), col2 = structure(c(1L, 1L, 2L, 2L, 3L, 
3L, 4L, 4L, 5L, 5L), .Label = c("7", "8", "10", "3", "4"), class = "factor"), 
    col3 = c(40L, 40L, 50L, 50L, 60L, 60L, 70L, 70L, 80L, 80L
    ), col4 = c(1, 1, 0, 0, 1, 1, 0, 0, 1, 1), col5 = c(JL, JL, KL, KL, LL, LL, ML, ML, NL, 
    NL), col6 = c(3.985645, 1.458798, 5.00212, 9.02336, 1.451203, 1.65653, 5.323211,  
    4.36969, 8.123256, 7.9632145), col7 = c(4.231623, 7.652123, 8.369562, 1.2120145,  
    5.321455, 2.369898, 1.147852, 5.231478, 9.2356478, 0.004555), col8 = c(2.36987,  
    1.236985, 7.4569852, 3.0014588, 8.25963, 8.2136999, 7.20014, 4.23698, 5.3696,  
    1.24789), col9 = c(9.36545852, 4.236987, 5.36692, 8.214569, 2.03369878, 7.21458777,  
    5.36989, 3.645478, 4.698889, 7.3696969), col10 = c(8.369663, 1.22556633, 4.6632121,  
    5.2223698, 4.3336988, 5.3366, 2.36555, 9.214563, 7.366695, 1.23655)), .Names =  
    c("col1", "col2", "col3", "col4", "col5", "col6", "col7", "col8", "col9", "col10"),  
    class = "data.frame", row.names = c(NA, -10L))

你应该谷歌搜索“R 查找重复行”,我很快就看到了很多相关内容,包括这个链接:https://dev59.com/1WYr5IYBdhLWcg3wFGVS。 - Michael Bellhouse
提示:http://stackoverflow.com/search?q=[r]+remove+duplicate+rows - user3710546
aggregate(. ~ col1 + col2, data = dd, FUN = mean) 在大型数据框中可能会变慢,然而。 - rawr
感谢您提供的信息。 - user4337967
我提供的输出是为了举例,但是与第6列相同的方法。 - user4337967
显示剩余2条评论
2个回答

3

这里使用的是dplyr,它在处理大量数据时速度非常快。首先提取不参与聚合的唯一列,然后进行聚合计算(按col1分组求均值)。最后将两部分拼接在一起(使用bind_cols)。我重命名了你的列名以删除空格,如果你保留了空格,则需要使用反引号(例如 `col 1`)。

library(dplyr)
cols <- 6:10  # columns to average
bind_cols(
    dat %>% distinct(col1) %>% .[,-cols],  # pull out columns we aren't aggregating
    dat[,c(1, cols)] %>% group_by(col1) %>%
        summarise_each(funs(mean)) %>% .[,-1]  # aggregate other columns
)

#    col1 col2 col3 col4 col5      col6       col7      col8      col9      col10
# 1 A-001    7   40    1    J   2.49282    5.94187   1.80343   6.80122    4.79762
# 2 B-002    8   50    0    K   7.01274    4.79079   5.22922   6.79075    4.94279
# 3 C-003   10   60    1    L   1.55387    3.84568   8.23667   4.62414    4.83515
# 4 D-004    3   70    0    M   4.84645    3.18967   5.71856   4.50768    5.79006
# 5 E-005    4   80    1    N   8.04324    4.62010   3.30875   6.03429    4.30162

编辑

这个过程非常复杂,感谢@StevenBeaupré,现在有了一个简单版本(*_each函数当然可以删除列!)。

dat %>% group_by(col1) %>% mutate_each(funs(mean), -(1:5)) %>% distinct

谢谢你的方法帮了我,我真的很感激,我会尝试在原始数据集上使用这种方法,并看看它是如何工作的。 - user4337967
当我运行代码时,样本的平均值运行得非常好,但其他列和ID会被复制。 - user4337967
没关系,是我自己的错误,代码没问题,现在我已经修复了这个错误。谢谢。 - user4337967
2
这看起来过于复杂了。为什么不直接使用以下代码: dd %>% group_by(col1) %>% mutate_each(funs(mean), -(1:5)) %>% distinct - Steven Beaupré
1
@StevenBeaupré 哦,太好了!我能用那个更新一下吗? - Rorschach

2

使用 data.table

library(data.table)#v1.9.5+
cols <- 6:10
setDT(dd)[, lapply(.SD, mean), by=c(names(dd)[1:5]), .SDcols=cols]
#    col1 col2 col3 col4 col5      col6       col7      col8      col9
#1: A-001    7   40    1    J   2.49282    5.94187   1.80343   6.80122
#2: B-002    8   50    0    K   7.01274    4.79079   5.22922   6.79075
#3: C-003   10   60    1    L   1.55387    3.84568   8.23667   4.62414
#4: D-004    3   70    0    M   4.84645    3.18967   5.71856   4.50768
#5: E-005    4   80    1    N   8.04324    4.62010   3.30875   6.03429
#     col10
#1: 4.79762
#2: 4.94279
#3: 4.83515
#4: 5.79006
#5: 4.30162

注意:在提供的示例中,每个'col1'组的第2到第5列值都相同。因此,我们可以使用1:5列作为分组变量。

如果对于每个'col1'变量,col2:col5中唯一值的长度>1,并且想要保留每个col1组的col2:col5的第一行

DT1 <- setDT(dd)[, lapply(.SD, mean), by = col1, .SDcols=cols]
setkey(unique(dd[,-cols, with=FALSE], by='col1'),col1)[DT1]
#    col1 col2 col3 col4 col5      col6       col7      col8      col9
#1: A-001    7   40    1    J   2.49282    5.94187   1.80343   6.80122
#2: B-002    8   50    0    K   7.01274    4.79079   5.22922   6.79075
#3: C-003   10   60    1    L   1.55387    3.84568   8.23667   4.62414
#4: D-004    3   70    0    M   4.84645    3.18967   5.71856   4.50768
#5: E-005    4   80    1    N   8.04324    4.62010   3.30875   6.03429
#     col10
#1: 4.79762
#2: 4.94279
#3: 4.83515
#4: 5.79006
#5: 4.30162

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接