programing

data.목록에 대한 행 프레임

closeapi 2023. 7. 10. 22:23
반응형

data.목록에 대한 행 프레임

저는 data.frame을 가지고 있는데, 행별로 목록으로 변환하고 싶습니다. 즉, 각 행은 고유한 목록 요소에 해당합니다.즉, data.frame에 행이 있는 목록을 원합니다.

지금까지 저는 이 문제를 다음과 같은 방식으로 다루었는데, 이 문제에 더 잘 접근할 수 있는 방법이 없을까 생각했습니다.

xy.df <- data.frame(x = runif(10),  y = runif(10))

# pre-allocate a list and fill it with a loop
xy.list <- vector("list", nrow(xy.df))
for (i in 1:nrow(xy.df)) {
    xy.list[[i]] <- xy.df[i,]
}

다음과 같이:

xy.list <- split(xy.df, seq(nrow(xy.df)))

그리고 만약 당신이 의 이름을 원한다면.xy.df출력 목록의 이름이 되기 위해 다음을 수행할 수 있습니다.

xy.list <- setNames(split(xy.df, seq(nrow(xy.df))), rownames(xy.df))

유레카!

xy.list <- as.list(as.data.frame(t(xy.df)))

보다 현대적인 솔루션에서는purrr::transpose:

library(purrr)
iris[1:2,] %>% purrr::transpose()
#> [[1]]
#> [[1]]$Sepal.Length
#> [1] 5.1
#> 
#> [[1]]$Sepal.Width
#> [1] 3.5
#> 
#> [[1]]$Petal.Length
#> [1] 1.4
#> 
#> [[1]]$Petal.Width
#> [1] 0.2
#> 
#> [[1]]$Species
#> [1] 1
#> 
#> 
#> [[2]]
#> [[2]]$Sepal.Length
#> [1] 4.9
#> 
#> [[2]]$Sepal.Width
#> [1] 3
#> 
#> [[2]]$Petal.Length
#> [1] 1.4
#> 
#> [[2]]$Petal.Width
#> [1] 0.2
#> 
#> [[2]]$Species
#> [1] 1

만약 당신이 (나처럼) data.frame을 완전히 남용하고 $ 기능을 유지하고 싶다면, 한 가지 방법은 당신에게 data.frame을 목록에 수집된 한 줄의 data.frame으로 분할하는 것입니다.

> df = data.frame(x=c('a','b','c'), y=3:1)
> df
  x y
1 a 3
2 b 2
3 c 1

# 'convert' into a list of data.frames
ldf = lapply(as.list(1:dim(df)[1]), function(x) df[x[1],])

> ldf
[[1]]
x y
1 a 3    
[[2]]
x y
2 b 2
[[3]]
x y
3 c 1

# and the 'coolest'
> ldf[[2]]$y
[1] 2

지적 자위일 뿐만 아니라 data.frame을 라인 목록으로 '변환'할 수 있으며, lapply와 함께 추가로 사용할 때 유용한 $인덱스를 유지합니다(lapply로 전달한 함수가 이 $인덱스를 사용한다고 가정합니다.

몇 가지 추가 옵션:

와 함께asplit

asplit(xy.df, 1)
#[[1]]
#     x      y 
#0.1137 0.6936 

#[[2]]
#     x      y 
#0.6223 0.5450 

#[[3]]
#     x      y 
#0.6093 0.2827 
#....

와 함께split그리고.row

split(xy.df, row(xy.df)[, 1])

#$`1`
#       x      y
#1 0.1137 0.6936

#$`2`
#       x     y
#2 0.6223 0.545

#$`3`
#       x      y
#3 0.6093 0.2827
#....

데이터.

set.seed(1234)
xy.df <- data.frame(x = runif(10),  y = runif(10))

저는 오늘 수백만 개의 관측치와 35개의 열이 있는 data.frame(실제로는 data.table)을 위해 이 작업을 하고 있었습니다.제 목표는 각각 하나의 행이 있는 data.frames(data.table) 목록을 반환하는 것이었습니다.즉, 각 행을 별도의 data.frame으로 분할하여 목록에 저장하고자 했습니다.

여기 제가 생각해 낸 두 가지 방법이 있는데, 대략 3배 더 빠릅니다.split(dat, seq_len(nrow(dat)))해당 데이터 세트의 경우.아래에서는 7500행, 5열 데이터 세트(홍채가 50회 반복됨)에 대한 세 가지 방법을 벤치마킹합니다.

library(data.table)
library(microbenchmark)

microbenchmark(
split={dat1 <- split(dat, seq_len(nrow(dat)))},
setDF={dat2 <- lapply(seq_len(nrow(dat)),
                  function(i) setDF(lapply(dat, "[", i)))},
attrDT={dat3 <- lapply(seq_len(nrow(dat)),
           function(i) {
             tmp <- lapply(dat, "[", i)
             attr(tmp, "class") <- c("data.table", "data.frame")
             setDF(tmp)
           })},
datList = {datL <- lapply(seq_len(nrow(dat)),
                          function(i) lapply(dat, "[", i))},
times=20
) 

반환됩니다.

Unit: milliseconds
       expr      min       lq     mean   median        uq       max neval
      split 861.8126 889.1849 973.5294 943.2288 1041.7206 1250.6150    20
      setDF 459.0577 466.3432 511.2656 482.1943  500.6958  750.6635    20
     attrDT 399.1999 409.6316 461.6454 422.5436  490.5620  717.6355    20
    datList 192.1175 201.9896 241.4726 208.4535  246.4299  411.2097    20

이전 테스트만큼 차이가 크지는 않지만, 직선입니다.setDFmax(set)를 갖는 런 분포의 모든 수준에서 방법이 훨씬 빠릅니다.DF) < min(분할) 및attr방법은 일반적으로 두 배 이상 빠릅니다.

네 번째 방법은 단순 내포된 극한 챔피언입니다.lapply중첩된 목록을 반환합니다.이 방법은 목록에서 data.frame을 구성하는 비용을 예시합니다.게다가, 제가 시도한 모든 방법들은data.frame함수는 대략 그것보다 몇 배 느렸습니다.data.table기술.

데이터.

dat <- vector("list", 50)
for(i in 1:50) dat[[i]] <- iris
dat <- setDF(rbindlist(dat))

의 최신 버전인 것 같습니다.purrr(0.2.2) 패키지가 가장 빠른 솔루션입니다.

by_row(x, function(v) list(v)[[1L]], .collate = "list")$.out

가장 흥미로운 솔루션을 비교해 보겠습니다.

data("Batting", package = "Lahman")
x <- Batting[1:10000, 1:10]
library(benchr)
library(purrr)
benchmark(
    split = split(x, seq_len(.row_names_info(x, 2L))),
    mapply = .mapply(function(...) structure(list(...), class = "data.frame", row.names = 1L), x, NULL),
    purrr = by_row(x, function(v) list(v)[[1L]], .collate = "list")$.out
)

결과:

Benchmark summary:
Time units : milliseconds 
  expr n.eval   min  lw.qu median   mean  up.qu  max  total relative
 split    100 983.0 1060.0 1130.0 1130.0 1180.0 1450 113000     34.3
mapply    100 826.0  894.0  963.0  972.0 1030.0 1320  97200     29.3
 purrr    100  24.1   28.6   32.9   44.9   40.5  183   4490      1.0

는 또한우같결얻수있을다니습과를은는리▁with▁result▁same다있▁also니▁the▁get로 같은 결과를 얻을 수 있습니다.Rcpp:

#include <Rcpp.h>
using namespace Rcpp;

// [[Rcpp::export]]
List df2list(const DataFrame& x) {
    std::size_t nrows = x.rows();
    std::size_t ncols = x.cols();
    CharacterVector nms = x.names();
    List res(no_init(nrows));
    for (std::size_t i = 0; i < nrows; ++i) {
        List tmp(no_init(ncols));
        for (std::size_t j = 0; j < ncols; ++j) {
            switch(TYPEOF(x[j])) {
                case INTSXP: {
                    if (Rf_isFactor(x[j])) {
                        IntegerVector t = as<IntegerVector>(x[j]);
                        RObject t2 = wrap(t[i]);
                        t2.attr("class") = "factor";
                        t2.attr("levels") = t.attr("levels");
                        tmp[j] = t2;
                    } else {
                        tmp[j] = as<IntegerVector>(x[j])[i];
                    }
                    break;
                }
                case LGLSXP: {
                    tmp[j] = as<LogicalVector>(x[j])[i];
                    break;
                }
                case CPLXSXP: {
                    tmp[j] = as<ComplexVector>(x[j])[i];
                    break;
                }
                case REALSXP: {
                    tmp[j] = as<NumericVector>(x[j])[i];
                    break;
                }
                case STRSXP: {
                    tmp[j] = as<std::string>(as<CharacterVector>(x[j])[i]);
                    break;
                }
                default: stop("Unsupported type '%s'.", type2name(x));
            }
        }
        tmp.attr("class") = "data.frame";
        tmp.attr("row.names") = 1;
        tmp.attr("names") = nms;
        res[i] = tmp;
    }
    res.attr("names") = x.attr("row.names");
    return res;
}

이제와비보십오시해교오보와 비교해 .purrr:

benchmark(
    purrr = by_row(x, function(v) list(v)[[1L]], .collate = "list")$.out,
    rcpp = df2list(x)
)

결과:

Benchmark summary:
Time units : milliseconds 
 expr n.eval  min lw.qu median mean up.qu   max total relative
purrr    100 25.2  29.8   37.5 43.4  44.2 159.0  4340      1.1
 rcpp    100 19.0  27.9   34.3 35.8  37.2  93.8  3580      1.0

한 후 apply 를 다 방 df 행 로 변 른 환 목 적 것 입 니 는 다 하 용 을 록 다 음 한 렬 법 은 ▁the 니 ▁an 것 ▁apply ▁list 다 입 ▁is ▁applying ▁then ▁to ▁convert ative ▁waylappy it: 그에대한기능것:ldf <- lapply(as.matrix(myDF), function(x)x)

나에게 가장 좋은 방법은:

예제 데이터:

Var1<-c("X1",X2","X3")
Var2<-c("X1",X2","X3")
Var3<-c("X1",X2","X3")

Data<-cbind(Var1,Var2,Var3)

ID    Var1   Var2  Var3 
1      X1     X2    X3
2      X4     X5    X6
3      X7     X8    X9

우리는 그것을 부릅니다.BBmisc

library(BBmisc)

data$lists<-convertRowsToList(data[,2:4])

결과는 다음과 같습니다.

ID    Var1   Var2  Var3  lists
1      X1     X2    X3   list("X1", "X2", X3") 
2      X4     X5    X6   list("X4","X5", "X6") 
3      X7     X8    X9   list("X7,"X8,"X9) 

@flodel이 쓴 것처럼:그러면 데이터 프레임이 데이터 프레임의 행 수와 동일한 수의 요소를 가진 목록으로 변환됩니다.

NewList <- split(df, f = seq(nrow(df)))

목록의 각 요소에서 NA가 아닌 열만 선택하는 기능을 추가할 수 있습니다.

NewList2 <- lapply(NewList, function(x) x[,!is.na(x)])

다을사용다대안른는을 사용하는 다른 .library(purrr) data더 것

flatten(by_row(xy.df, ..f = function(x) flatten_chr(x), .labels = FALSE))

by_rowpurrrlyr패키지가 당신을 위해 이것을 할 것입니다.

이 예는 다음을 보여줍니다.

myfn <- function(row) {
  #row is a tibble with one row, and the same number of columns as the original df
  l <- as.list(row)
  return(l)
}

list_of_lists <- purrrlyr::by_row(df, myfn, .labels=FALSE)$.out

기적으 값된은에서 된 값입니다.myfn라고 불리는 df의 새 목록 열에 들어갑니다..out.$.out위의 문 끝에서 이 열을 즉시 선택하여 목록 목록을 반환합니다.

언급URL : https://stackoverflow.com/questions/3492379/data-frame-rows-to-a-list

반응형