r - 按组选择第一行

标签 r dataframe sqldf

来自这样的数据框

test <- data.frame('id'= rep(1:5,2), 'string'= LETTERS[1:10])
test <- test[order(test$id), ]
rownames(test) <- 1:10

> test
    id string
 1   1      A
 2   1      F
 3   2      B
 4   2      G
 5   3      C
 6   3      H
 7   4      D
 8   4      I
 9   5      E
 10  5      J

我想用每个 id/字符串对的第一行创建一个新的。如果 sqldf 接受其中的 R 代码,则查询可能如下所示:

res <- sqldf("select id, min(rownames(test)), string 
              from test 
              group by id, string")

> res
    id string
 1   1      A
 3   2      B
 5   3      C
 7   4      D
 9   5      E

是否有除了创建新列之外的解决方案

test$row <- rownames(test)

并使用 min(row) 运行相同的 sqldf 查询?

最佳答案

您可以使用duplicate来非常快速地完成此操作。

test[!duplicated(test$id),]

对于速度狂来说的基准:

ju <- function() test[!duplicated(test$id),]
gs1 <- function() do.call(rbind, lapply(split(test, test$id), head, 1))
gs2 <- function() do.call(rbind, lapply(split(test, test$id), `[`, 1, ))
jply <- function() ddply(test,.(id),function(x) head(x,1))
jdt <- function() {
  testd <- as.data.table(test)
  setkey(testd,id)
  # Initial solution (slow)
  # testd[,lapply(.SD,function(x) head(x,1)),by = key(testd)]
  # Faster options :
  testd[!duplicated(id)]               # (1)
  # testd[, .SD[1L], by=key(testd)]    # (2)
  # testd[J(unique(id)),mult="first"]  # (3)
  # testd[ testd[,.I[1L],by=id] ]      # (4) needs v1.8.3. Allows 2nd, 3rd etc
}

library(plyr)
library(data.table)
library(rbenchmark)

# sample data
set.seed(21)
test <- data.frame(id=sample(1e3, 1e5, TRUE), string=sample(LETTERS, 1e5, TRUE))
test <- test[order(test$id), ]

benchmark(ju(), gs1(), gs2(), jply(), jdt(),
    replications=5, order="relative")[,1:6]
#     test replications elapsed relative user.self sys.self
# 1   ju()            5    0.03    1.000      0.03     0.00
# 5  jdt()            5    0.03    1.000      0.03     0.00
# 3  gs2()            5    3.49  116.333      2.87     0.58
# 2  gs1()            5    3.58  119.333      3.00     0.58
# 4 jply()            5    3.69  123.000      3.11     0.51

让我们再试一次,但只使用第一轮比赛的竞争者,并使用更多数据和更多重复。

set.seed(21)
test <- data.frame(id=sample(1e4, 1e6, TRUE), string=sample(LETTERS, 1e6, TRUE))
test <- test[order(test$id), ]
benchmark(ju(), jdt(), order="relative")[,1:6]
#    test replications elapsed relative user.self sys.self
# 1  ju()          100    5.48    1.000      4.44     1.00
# 2 jdt()          100    6.92    1.263      5.70     1.15

关于r - 按组选择第一行,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13279582/

相关文章:

python - Pandas 将时间序列数据重新采样为 15 分钟和 45 分钟 - 使用多索引或列

r - sqldf 在排序时将数字列更改为字符 1

R - sqldf() 返回零行数据框

r - 有没有一种快速计算多列乘法结果的方法,但根据 NA 值具有不同的比例?

arrays - 根据一列中数组的元素选择数据框的行

r - sqldf : create table from data frame error: "no such table". 和创建了两个表而不是一个

r - 如何检查矩阵在R语言中是否有逆矩阵

r - 查找具有特定参数的函数

r - 如何将 ggplot 与 prop.table(table(x) 一起使用?

r - 如何使用 R 计算 Tanimoto/Jacquard Score 作为距离矩阵