>

필드 중 하나가 합성 (구분) 인 R에 데이터 프레임이 있습니다. 내가 가진 것의 예는 다음과 같습니다.

users=c(1,2,3)
items=c("23 77 49", "10 18 28", "20 31 84")
df = data.frame(users,items)

(구축하지는 않습니다. 이것은 단지 설명을위한 것입니다.)

 users    items
  1        23 77 49
  2        10 18 28
  3        20 31 84

고유하지 않은 사용자 ID 목록과 행당 개별 항목을 갖기 위해 두 번째 열을 병합하려고합니다. 그래서 나는 다음과 같이 끝내고 싶다 :

user   item
1        23
1        77
1        49
2        10
2        18
2        28
3        20
3        31
3        84

내가 시도했다 :

data.frame(user = df$users, item = unlist(strsplit(as.character(df$items), " ")))

그러나 "인수는 다른 행 수를 암시합니다"라는 메시지가 나타납니다. 이유를 이해하지만 원하는 결과를 얻을 수있는 솔루션을 찾을 수 없습니다. 어떤 아이디어?

또한 2 천만 행이 넘는 가장 효율적인 방법은 무엇입니까?


  • 답변 # 1

    items <- strsplit(df$items, " ")
    data.frame(user = rep(df$users, sapply(items, length)), item = unlist(items))
    ##   user item                                                                                                                                                                                                                                
    ## 1    1   23                                                                                                                                                                                                                                
    ## 2    1   77                                                                                                                                                                                                                                
    ## 3    1   49                                                                                                                                                                                                                                
    ## 4    2   10                                                                                                                                                                                                                                
    ## 5    2   18                                                                                                                                                                                                                                
    ## 6    2   28                                                                                                                                                                                                                                
    ## 7    3   20                                                                                                                                                                                                                                
    ## 8    3   31                                                                                                                                                                                                                                
    ## 9    3   84 
    
    

    또는

    library(data.table)
    DT <- data.table(df)    
    DT[, list(item = unlist(strsplit(items, " "))), by = users]
    ##    users item                                                                                                                                                                                                                              
    ## 1:     1   23                                                                                                                                                                                                                              
    ## 2:     1   77                                                                                                                                                                                                                              
    ## 3:     1   49                                                                                                                                                                                                                              
    ## 4:     2   10                                                                                                                                                                                                                              
    ## 5:     2   18                                                                                                                                                                                                                              
    ## 6:     2   28                                                                                                                                                                                                                              
    ## 7:     3   20                                                                                                                                                                                                                              
    ## 8:     3   31                                                                                                                                                                                                                              
    ## 9:     3   84
    
    

  • 답변 # 2

    와이즈 비즈는  해결책

    dplyr
    
    

    와이즈 비즈가 있으면 정말 좋을 것 같아  기능, 즉 users=c(1,2,3) items=c("23 77 49", "10 18 28", "20 31 84") df = data.frame(users,items,stringsAsFactors=FALSE) rbind_all(do(df %.% group_by(users), .f = function(d) data.frame(d[,1,drop=FALSE], items = unlist(strsplit(d[['items']],' ')), stringsAsFactors=FALSE))) 의 반대

    예 : 다음과 같이 작동하면

    expand
    
    

  • 답변 # 3

    "SOfun"패키지를 설치하거나 summarise 를로드하려면  함수, 그리고 각 "항목"문자열에 동일한 수의 항목이있는 경우 (예 : 3 개) 다음 옵션이 있습니다.

    df %.% group_by(users) %.% expand(unlist(strsplit(items,' ')))
    
    

    예제입니다.

    샘플 데이터 : 3 행, 3000 행 및 3,000,000 행

    두 가지 옵션의 결과를 비교할 수 있도록 "id"열을 추가했습니다.

    concat.split.DT
    
    
    필요한 패키지로드 library(reshape2) library(data.table) melt(concat.split.DT(indf, "items", " "), id.vars="users") 에 대한

    "SOfun"(GitHub에만 해당)   ## your sample data.frame df <- data.frame(users=c(1,2,3), items=c("23 77 49", "10 18 28", "20 31 84")) ## extended to 3000 rows df1k <- df[rep(rownames(df), 1000), ] df1k$id <- sequence(nrow(df1k)) ## extended to 3 million rows df1m <- df1M <- df[rep(rownames(df), 1000000), ] df1m$id <- sequence(nrow(df1m)) 를 사용하는  연결된 값을 분할하려면 "data.table"에서

    concat.split.DT 에 대한

    "reshape2"

    최고 버전 1.8.11의 "data.table"

    <시간>
    fread
    
    

    제이크의 답변 속도와이 기능을 테스트하는 기능이 있습니다. 나중에 "dplyr"로 업데이트하려고합니다.

    melt
    
    

    3,000 행 테스트

    # library(devtools)
    # install_github("SOfun", "mrdwab")
    library(SOfun)
    library(data.table)
    library(reshape2)
    packageVersion("data.table")
    # [1] ‘1.8.11’
    
    

    3,000,000 개의 행에서 한 번만 테스트

    시간은 초 단위입니다 ....

    fun1 <- function(indf) {
      DT <- melt(concat.split.DT(indf, "items", " "), 
                 id.vars=c("id", "users"))
      setkeyv(DT, c("id", "users"))
      DT
    }
    fun2 <- function(indf) {
      DT <- data.table(indf)    
      DT[, list(item = unlist(strsplit(as.character(items), " "))), 
         by = list(id, users)]
    }
    
    
    <시간> 업데이트

    @Jake는 "id"를 추가하면 타이밍에 큰 차이가 생겼다는 점에서 좋은 지적을합니다. 두 microbenchmark(fun1(df1k), fun2(df1k)) # Unit: milliseconds # expr min lq median uq max neval # fun1(df1k) 17.64675 18.21658 18.79859 21.21943 71.7737 100 # fun2(df1k) 152.97974 158.44148 163.12707 199.77297 345.7508 100 의 출력이되도록 추가했습니다.  결과는 동일하다는 것을 쉽게 알 수 있습니다

    system.time(fun1(df1m)) # user system elapsed # 7.71 0.94 8.69 system.time(fun2(df1m)) # user system elapsed # 177.80 0.50 178.97 에서 "id"열 제거 및 "id"에 대한 참조 제거  그리고 data.table  다음을 제공합니다 :

    fun1
    
    

    위의 벤치마킹은 fun2 입니다. @mnel의 "dplyr"접근 방식입니다.

    microbenchmark(fun1a(df1M), fun2a(df1M), fun3(df1M), times = 5)
    # Unit: seconds
    #         expr       min        lq    median        uq       max neval
    #  fun1a(df1M)  2.307313  2.420845  2.630284  2.822011  3.074464     5
    #  fun2a(df1M) 12.480502 12.491783 12.761392 13.069169 13.733686     5
    #   fun3(df1M) 13.976329 14.281856 14.471252 15.041450 15.089593     5
    
    

    아주 좋은 성능의 모든 답변!

    fun3

  • 이전 objective c - 단일 크기의 동적 UILabel 글꼴 만들기
  • 다음 php - 어떻게 hhmmss로 Unix timestamp를 변환합니까?