그룹별 첫 번째 행 선택
이와 같은 데이터 프레임에서
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(행)으로 동일한 sqldf 쿼리를 실행하시겠습니까?
사용할 수 있습니다.duplicated
이 일을 아주 빨리 하기 위해서.
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
저는 dplyr 접근법을 선호합니다.
group_by(id)
그 다음에 둘 중 하나가
filter(row_number()==1)
또는slice(1)
또는slice_head(1)
#(dplyr => 1.0)top_n(n = -1)
top_n()
내부적으로 순위 함수를 사용합니다.음수는 순위의 맨 아래에서 선택합니다.
경우에 따라 group_by 뒤에 id를 정렬해야 할 수 있습니다.
library(dplyr)
# using filter(), top_n() or slice()
m1 <-
test %>%
group_by(id) %>%
filter(row_number()==1)
m2 <-
test %>%
group_by(id) %>%
slice(1)
m3 <-
test %>%
group_by(id) %>%
top_n(n = -1)
세 가지 방법 모두 동일한 결과를 반환합니다.
# A tibble: 5 x 2
# Groups: id [5]
id string
<int> <fct>
1 1 A
2 2 B
3 3 C
4 4 D
5 5 E
어때
DT <- data.table(test)
setkey(DT, id)
DT[J(unique(id)), mult = "first"]
편집
에 대한 고유한 방법도 있습니다.data.tables
첫 번째 행을 키로 반환합니다.
jdtu <- function() unique(DT)
제 생각에, 만약 당신이 주문한다면.test
벤치마크를 벗어나면, 당신은 그것을 제거할 수 있습니다.setkey
그리고.data.table
벤치마크로부터의 변환도 마찬가지입니다(셋 키가 기본적으로 id별로 정렬되므로, 동일함).order
).
set.seed(21)
test <- data.frame(id=sample(1e3, 1e5, TRUE), string=sample(LETTERS, 1e5, TRUE))
test <- test[order(test$id), ]
DT <- data.table(DT, key = 'id')
ju <- function() test[!duplicated(test$id),]
jdt <- function() DT[J(unique(id)),mult = 'first']
library(rbenchmark)
benchmark(ju(), jdt(), replications = 5)
## test replications elapsed relative user.self sys.self
## 2 jdt() 5 0.01 1 0.02 0
## 1 ju() 5 0.05 5 0.05 0
그리고 더 많은 데이터와 함께
고유한 방법으로 편집**
set.seed(21)
test <- data.frame(id=sample(1e4, 1e6, TRUE), string=sample(LETTERS, 1e6, TRUE))
test <- test[order(test$id), ]
DT <- data.table(test, key = 'id')
test replications elapsed relative user.self sys.self
2 jdt() 5 0.09 2.25 0.09 0.00
3 jdtu() 5 0.04 1.00 0.05 0.00
1 ju() 5 0.22 5.50 0.19 0.03
독특한 방법이 여기서 가장 빠릅니다.
간단한ddply
옵션:
ddply(test,.(id),function(x) head(x,1))
속도가 문제인 경우, 유사한 접근 방식을 취할 수 있습니다.data.table
:
testd <- data.table(test)
setkey(testd,id)
testd[,.SD[1],by = key(testd)]
또는 이 작업이 상당히 빠를 수 있습니다.
testd[testd[, .I[1], by = key(testd]$V1]
자, 이제dplyr
고유 카운터를 추가합니다.
df %>%
group_by(aa, bb) %>%
summarise(first=head(value,1), count=n_distinct(value))
그룹을 만들고 그룹 내에서 요약합니다.
데이터가 숫자인 경우 다음을 사용할 수 있습니다.
first(value)
[또한 있습니다.last(value)
대신에head(value, 1)
참조: http://cran.rstudio.com/web/packages/dplyr/vignettes/introduction.html
전체:
> df
Source: local data frame [16 x 3]
aa bb value
1 1 1 GUT
2 1 1 PER
3 1 2 SUT
4 1 2 GUT
5 1 3 SUT
6 1 3 GUT
7 1 3 PER
8 2 1 221
9 2 1 224
10 2 1 239
11 2 2 217
12 2 2 221
13 2 2 224
14 3 1 GUT
15 3 1 HUL
16 3 1 GUT
> library(dplyr)
> df %>%
> group_by(aa, bb) %>%
> summarise(first=head(value,1), count=n_distinct(value))
Source: local data frame [6 x 4]
Groups: aa
aa bb first count
1 1 1 GUT 2
2 1 2 SUT 2
3 1 3 SUT 3
4 2 1 221 3
5 2 2 217 3
6 3 1 GUT 2
SQLite에는 기본 제공rowid
유사 열을 사용하여 다음 작업을 수행합니다.
sqldf("select min(rowid) rowid, id, string
from test
group by id")
제공:
rowid id string
1 1 1 A
2 3 2 B
3 5 3 C
4 7 4 D
5 9 5 E
또한sqldf
그 자체로row.names=
인수:
sqldf("select min(cast(row_names as real)) row_names, id, string
from test
group by id", row.names = TRUE)
제공:
id string
1 1 A
3 2 B
5 3 C
7 4 D
9 5 E
위의 두 가지 요소를 혼합하는 세 번째 대안이 훨씬 더 나을 수 있습니다.
sqldf("select min(rowid) row_names, id, string
from test
group by id", row.names = TRUE)
제공:
id string
1 1 A
3 2 B
5 3 C
7 4 D
9 5 E
이 세 가지 모두 SQL에 대한 SQLite 확장에 의존합니다. 여기서 사용되는 SQL은min
또는max
다른 열이 동일한 행에서 선택되도록 보장합니다. (다른 SQL 기반 데이터베이스에서는 보장되지 않을 수 있습니다.)
기본 R 옵션은 다음과 같습니다.split()
-lapply()
-do.call()
관용구:
> do.call(rbind, lapply(split(test, test$id), head, 1))
id string
1 1 A
2 2 B
3 3 C
4 4 D
5 5 E
보다 직접적인 방법은lapply()
그[
함수:
> do.call(rbind, lapply(split(test, test$id), `[`, 1, ))
id string
1 1 A
2 2 B
3 3 C
4 4 D
5 5 E
쉼표 공간1, )
말에lapply()
통화는 통화와 동일하기 때문에 필수입니다.[1, ]
첫 번째 행과 모든 열을 선택합니다.
dplyr 1.1.0
는 인인그사수있습다니용할과 함께 사용할 수 .slice_head
의 인수:
slice_head(test, n = 1, by = id)
# id string
# 1 1 A
# 2 2 B
# 3 3 C
# 4 4 D
# 5 5 E
언급URL : https://stackoverflow.com/questions/13279582/select-the-first-row-by-group
'programing' 카테고리의 다른 글
루비 형식으로 xlsx 파일 가져오기/내보내기를 지원하는 보석 (0) | 2023.06.14 |
---|---|
제공한 권한 부여 메커니즘이 지원되지 않습니다.AWS4-HMAC-SHA256을 사용하십시오. (0) | 2023.06.14 |
유형 스크립트를 사용하여 프로토타입 함수 정의 (0) | 2023.06.14 |
데이터 테이블을 필터링하려면 어떻게 해야 합니까? (0) | 2023.06.14 |
반환 *의 결과를 MariaDB에 어떻게 저장합니까? (0) | 2023.06.14 |