복붙노트

[SQL] 어떻게 R에서 SQL 순위 기능을 시뮬레이션?

SQL

어떻게 R에서 SQL 순위 기능을 시뮬레이션?

참조 http://www.orafaq.com/node/, 무엇 오라클 ROW_NUMBER (), RANK (), 또는 DENSE_RANK () ( "순서에 따라 행에 할당 정수 값"과 같은 순위 기능의 R 동등한입니다 55)?

나는 각 기능의 기능은 잠재적으로 임시 방식으로 달성 할 수 있음을 동의합니다. 하지만 내 주요 관심사는 성능이다. 그것은 메모리와 속도를 위해 가입 또는 색인 액세스를 사용하지 않는 것이 좋은 것입니다.

해결법

  1. ==============================

    1.data.table 패키지는, 특히 버전 1.8.1, 많은 SQL 측면에서 파티션의 기능의 제공으로 시작. R의 랭크 (X, ties.method = "분") 오라클 RANK ()와 유사하고, 모방 (후술) 요인 DENSE_RANK () 함수를 사용하는 방법이있다. 모방 ROW_NUMBER 할 수있는 방법은 말 명백해야한다.

    data.table 패키지는, 특히 버전 1.8.1, 많은 SQL 측면에서 파티션의 기능의 제공으로 시작. R의 랭크 (X, ties.method = "분") 오라클 RANK ()와 유사하고, 모방 (후술) 요인 DENSE_RANK () 함수를 사용하는 방법이있다. 모방 ROW_NUMBER 할 수있는 방법은 말 명백해야한다.

    다음은 그 예이다 : R-포지에서 data.table의 최신 버전을로드 :

    install.packages("data.table",
      repos= c("http://R-Forge.R-project.org", getOption("repos")))
    
    library(data.table)
    

    몇 가지 예를 들어 데이터를 만들기 :

    set.seed(10)
    
    DT<-data.table(ID=seq_len(4*3),group=rep(1:4,each=3),value=rnorm(4*3),
      info=c(sample(c("a","b"),4*2,replace=TRUE),
      sample(c("c","d"),4,replace=TRUE)),key="ID")
    
    > DT
        ID group       value info
     1:  1     1  0.01874617    a
     2:  2     1 -0.18425254    b
     3:  3     1 -1.37133055    b
     4:  4     2 -0.59916772    a
     5:  5     2  0.29454513    b
     6:  6     2  0.38979430    a
     7:  7     3 -1.20807618    b
     8:  8     3 -0.36367602    a
     9:  9     3 -1.62667268    c
    10: 10     4 -0.25647839    d
    11: 11     4  1.10177950    c
    12: 12     4  0.75578151    d
    

    순위 그룹 내에서 값을 감소시킴으로써, 각 ID합니다 (주의 - 값 앞의 순서 감소 나타내는데)

    > DT[,valRank:=rank(-value),by="group"]
        ID group       value info valRank
     1:  1     1  0.01874617    a       1
     2:  2     1 -0.18425254    b       2
     3:  3     1 -1.37133055    b       3
     4:  4     2 -0.59916772    a       3
     5:  5     2  0.29454513    b       2
     6:  6     2  0.38979430    a       1
     7:  7     3 -1.20807618    b       2
     8:  8     3 -0.36367602    a       1
     9:  9     3 -1.62667268    c       3
    10: 10     4 -0.25647839    d       3
    11: 11     4  1.10177950    c       1
    12: 12     4  0.75578151    d       2
    

    위를 기록하였고, 가치 관계와 DENSE_RANK ()의 경우, 당신은 인자로 값을 변환 한 후 기본 정수 값을 반환 할 수 있습니다. 예를 들어, 그룹 내의 정보에 기초하여 각각의 ID 순위 (infoRankDense infoRank와 비교) :

    DT[,infoRank:=rank(info,ties.method="min"),by="group"]
    DT[,infoRankDense:=as.integer(factor(info)),by="group"]
    
    R> DT
        ID group       value info valRank infoRank infoRankDense
     1:  1     1  0.01874617    a       1        1             1
     2:  2     1 -0.18425254    b       2        2             2
     3:  3     1 -1.37133055    b       3        2             2
     4:  4     2 -0.59916772    a       3        1             1
     5:  5     2  0.29454513    b       2        3             2
     6:  6     2  0.38979430    a       1        1             1
     7:  7     3 -1.20807618    b       2        2             2
     8:  8     3 -0.36367602    a       1        1             1
     9:  9     3 -1.62667268    c       3        3             3
    10: 10     4 -0.25647839    d       3        2             2
    11: 11     4  1.10177950    c       1        1             1
    12: 12     4  0.75578151    d       2        2             2
    

    추신. 안녕 매튜 Dowle.

    LEAD 및 LAG

    모방 LEAD 및 LAG를 들어, 여기에 제공된 답변을 시작합니다. 나는 그룹 내 ID의 순서에 따라 순위 변수를 만들 것입니다. 이는 상기와 가짜 데이터를 필요하지 않을 것입니다,하지만 ID를 그룹 내에서 순차적으로하지 않은 경우, 다음이 인생을 좀 더 어렵게 만들 것입니다. 그래서 여기에 비 순차적 ID를 가진 새로운 가짜 데이터입니다 :

    set.seed(10)
    
    DT<-data.table(ID=sample(seq_len(4*3)),group=rep(1:4,each=3),value=rnorm(4*3),
      info=c(sample(c("a","b"),4*2,replace=TRUE),
      sample(c("c","d"),4,replace=TRUE)),key="ID")
    
    DT[,idRank:=rank(ID),by="group"]
    setkey(DT,group, idRank)
    
    > DT
        ID group       value info idRank
     1:  4     1 -0.36367602    b      1
     2:  5     1 -1.62667268    b      2
     3:  7     1 -1.20807618    b      3
     4:  1     2  1.10177950    a      1
     5:  2     2  0.75578151    a      2
     6: 12     2 -0.25647839    b      3
     7:  3     3  0.74139013    c      1
     8:  6     3  0.98744470    b      2
     9:  9     3 -0.23823356    a      3
    10:  8     4 -0.19515038    c      1
    11: 10     4  0.08934727    c      2
    12: 11     4 -0.95494386    c      3
    

    그런 다음, 이전 한 레코드의 값을 가져 그룹과 idRank 변수를 사용하고 idRank에서 1을 빼고 다 = '마지막'인수를 사용합니다. 두 항목 위의 기록에서 값을 얻으려면 2를 뺍니다.

    DT[,prev:=DT[J(group,idRank-1), value, mult='last']]
    DT[,prev2:=DT[J(group,idRank-2), value, mult='last']]
    
        ID group       value info idRank        prev      prev2
     1:  4     1 -0.36367602    b      1          NA         NA
     2:  5     1 -1.62667268    b      2 -0.36367602         NA
     3:  7     1 -1.20807618    b      3 -1.62667268 -0.3636760
     4:  1     2  1.10177950    a      1          NA         NA
     5:  2     2  0.75578151    a      2  1.10177950         NA
     6: 12     2 -0.25647839    b      3  0.75578151  1.1017795
     7:  3     3  0.74139013    c      1          NA         NA
     8:  6     3  0.98744470    b      2  0.74139013         NA
     9:  9     3 -0.23823356    a      3  0.98744470  0.7413901
    10:  8     4 -0.19515038    c      1          NA         NA
    11: 10     4  0.08934727    c      2 -0.19515038         NA
    12: 11     4 -0.95494386    c      3  0.08934727 -0.1951504
    

    LEAD를 들어, '제'= 다중 행 idRank 변수와 스위치에 적절한 오프셋을 추가

    DT[,nex:=DT[J(group,idRank+1), value, mult='first']]
    DT[,nex2:=DT[J(group,idRank+2), value, mult='first']]
    
        ID group       value info idRank        prev      prev2         nex       nex2
     1:  4     1 -0.36367602    b      1          NA         NA -1.62667268 -1.2080762
     2:  5     1 -1.62667268    b      2 -0.36367602         NA -1.20807618         NA
     3:  7     1 -1.20807618    b      3 -1.62667268 -0.3636760          NA         NA
     4:  1     2  1.10177950    a      1          NA         NA  0.75578151 -0.2564784
     5:  2     2  0.75578151    a      2  1.10177950         NA -0.25647839         NA
     6: 12     2 -0.25647839    b      3  0.75578151  1.1017795          NA         NA
     7:  3     3  0.74139013    c      1          NA         NA  0.98744470 -0.2382336
     8:  6     3  0.98744470    b      2  0.74139013         NA -0.23823356         NA
     9:  9     3 -0.23823356    a      3  0.98744470  0.7413901          NA         NA
    10:  8     4 -0.19515038    c      1          NA         NA  0.08934727 -0.9549439
    11: 10     4  0.08934727    c      2 -0.19515038         NA -0.95494386         NA
    12: 11     4 -0.95494386    c      3  0.08934727 -0.1951504          NA         NA
    
  2. ==============================

    2.data.table v1.9.5의 +에서 구현되었습니다 (빠른 순위에 대한)) (프랭크 작동합니다. frankv로 (가)와 쉽게 프로그래밍 할 수 있습니다 어디 프랭크 () 대화 형 시나리오에서 유용합니다.

    data.table v1.9.5의 +에서 구현되었습니다 (빠른 순위에 대한)) (프랭크 작동합니다. frankv로 (가)와 쉽게 프로그래밍 할 수 있습니다 어디 프랭크 () 대화 형 시나리오에서 유용합니다.

    그것은 기본 :: 계급에서 사용할 수있는 모든 작업을 구현합니다. 또한, 장점은 다음과 같습니다

    여기 @BenBarnes '(우수) 포스트에서 같은 data.table DT를 사용하여 위의 모든 점의 그림입니다.

    require(data.table)
    set.seed(10)
    sample_n <- function(x, n) sample(x, n, replace=TRUE)
    DT <- data.table(
            ID = seq_len(4*3),
            group = rep(1:4,each=3),
            value = rnorm(4*3),
            info = c(sample_n(letters[1:2], 8), sample_n(letters[3:4], 4)))
    

    또한, 최대 무작위, 평균 먼저 다른 방법의 분을 사용할 수 있습니다.

    당신은 데이터의 하위 집합을 의미하고 그 그룹에 해당하는 데이터를 포함 .SD를 사용할 수 있습니다. .SD에 대한 자세한 내용은 data.table HTML 비네팅에 대한 소개를 참조하십시오.

    당신은 유사 frankv 사용 COLS 인수와 열이 순서 인수를 사용하여 평가해야하는 순서에 열을 제공 할 수 있습니다.

    기본 :: 순위와 비교하는 작은 벤치 마크 :

    set.seed(45L)
    x = sample(1e4, 1e7, TRUE)
    system.time(ans1 <- base::rank(x, ties.method="first"))
    #    user  system elapsed 
    #  22.200   0.255  22.536 
    system.time(ans2 <- frank(x, ties.method="first"))
    #    user  system elapsed 
    #   0.745   0.014   0.762 
    identical(ans1, ans2) # [1] TRUE
    
  3. ==============================

    3.나는 다음 사람만큼 data.table 좋아하지만 항상 필요는 없습니다. data.table 항상 빠른 수 있지만, 심지어 그룹의 수는 상당히 작은 경우 적당히 대용량 데이터 세트에 대한 plyr는 여전히 적절하게 수행합니다.

    나는 다음 사람만큼 data.table 좋아하지만 항상 필요는 없습니다. data.table 항상 빠른 수 있지만, 심지어 그룹의 수는 상당히 작은 경우 적당히 대용량 데이터 세트에 대한 plyr는 여전히 적절하게 수행합니다.

    무엇 벤 반스가 data.tables이 같은 컴팩트 단지 다 (그러나 나는 아마 느린 많은 경우에 이전에 언급 한 바와 같이) plyr를 사용 할 수 있습니다 사용했다 :

    library(plyr)                
    ddply(DT,.(group),transform,valRank = rank(-value))
    ddply(DT,.(group),transform,valRank = rank(info,ties.method = "min"),
                                valRankDense = as.integer(factor(info)))
    

    심지어 모두에 하나의 추가 패키지를로드하지 않고 :

    do.call(rbind,by(DT,DT$group,transform,valRank = rank(-value)))
    do.call(rbind,by(DT,DT$group,transform,valRank = rank(info,ties.method = "min"),
                                            valRankDense = as.integer(factor(info))))
    

    당신이 비록 마지막 경우 구문 미묘한의 일부를 잃게됩니다.

  4. ==============================

    4.나는 오라클의 분석 기능에 직접 해당하는이 있다고 생각하지 않습니다. Plyr 가능성이 있지만 모든 직접적 분석 기능의 일부를 달성 할 수있을 것입니다. 나는 R 별도로 각각의 기능을 복제 할 수 있습니다 확신하지만 난 모든 것을 할 것입니다 단일 패키지가 있다고 생각하지 않습니다.

    나는 오라클의 분석 기능에 직접 해당하는이 있다고 생각하지 않습니다. Plyr 가능성이 있지만 모든 직접적 분석 기능의 일부를 달성 할 수있을 것입니다. 나는 R 별도로 각각의 기능을 복제 할 수 있습니다 확신하지만 난 모든 것을 할 것입니다 단일 패키지가 있다고 생각하지 않습니다.

    당신이 R에 달성하는 데 필요한 특정 작업이 있다면, 다음 몇 가지 인터넷 검색을 수행하고 빈 올 경우에 StackOverflow 여기에 특정 질문을 부탁드립니다.

  5. from https://stackoverflow.com/questions/11446254/how-to-emulate-sqls-rank-functions-in-r by cc-by-sa and MIT license