programing

FUN 내부의 응용프로그램 인덱스 이름에 액세스합니다.

showcode 2023. 6. 14. 22:00
반응형

FUN 내부의 응용프로그램 인덱스 이름에 액세스합니다.

lapply() 함수에서 목록 인덱스 이름을 가져올 수 있는 방법이 있습니까?

n = names(mylist)
lapply(mylist, function(list.elem) { cat("What is the name of this list element?\n" })

이전에 lapply() 반환된 목록에서 인덱스 이름을 보존할 수 있는지 문의했지만 사용자 지정 함수 내에서 각 요소 이름을 쉽게 가져올 수 있는 방법이 있는지는 아직 모르겠습니다.이름 자체에 대한 호출을 피하고 싶습니다. 함수 매개 변수에 이름을 입력하고 싶습니다.

불하게도행,,lapply통과하는 벡터의 요소만 제공합니다.일반적인 해결 방법은 벡터 자체 대신 벡터의 이름이나 인덱스를 전달하는 것입니다.

그러나 항상 추가 인수를 함수에 전달할 수 있으므로 다음이 작동합니다.

x <- list(a=11,b=12,c=13) # Changed to list to address concerns in commments
lapply(seq_along(x), function(y, n, i) { paste(n[[i]], y[[i]]) }, y=x, n=names(x))

사용하는 위치lapply 넘는을의 .x그러나 또한 전달합니다.x 및의이의 .x보시다시피, 함수 인수의 순서는 다음과 같습니다.lapply추가 인수 중에 지정되지 않은 첫 번째 인수에 "인덱스"(여기서는 인덱스)를 전달합니다.이 경우에는 다음과 같이 지정합니다.y그리고.n그서오밖에 없어요.i왼쪽...

다음을 생성합니다.

[[1]]
[1] "a 11"

[[2]]
[1] "b 12"

[[3]]
[1] "c 13"

업데이트 더 간단한 예, 동일한 결과:

lapply(seq_along(x), function(i) paste(names(x)[[i]], x[[i]]))

는 " "글로벌"을 사용합니다.x각 통화의 이름을 추출합니다.

토미와 하지만, 이작은기토동미일해사방만용지하법결을한와로본으적업,▁this▁with만사▁basically▁but▁the지용,Map()목록 구성 요소의 이름을 저장하는 전역 변수에 액세스할 필요가 없습니다.

> x <- list(a=11, b=12, c=13)
> Map(function(x, i) paste(i, x), x, names(x))
$a
[1] "a 11"

$b
[1] "b 12"

$c
[1] "c 13

아니면, 당신이 원한다면,mapply()

> mapply(function(x, i) paste(i, x), x, names(x))
     a      b      c 
"a 11" "b 12" "c 13"

R 버전 3.2 업데이트

고지 사항: 이것은 진부한 속임수이며, 다음 릴리스에서 작동을 멈출 수 있습니다.

다음을 사용하여 인덱스를 가져올 수 있습니다.

> lapply(list(a=10,b=20), function(x){parent.frame()$i[]})
$a
[1] 1

$b
[1] 2

고: 더[]R이 기호를 생각하도록 속이기 때문에 이것이 작동하기 위해 필요합니다.i됨)lapply에 더 많은 수 참조의 할 수 있습니다에 더 많은 참조가 있을 수 있으므로 해당 참조의 느린 복제를 활성화할 수 있습니다.이것이 없으면, R은 분리된 복사본을 보관하지 않을 것입니다.i:

> lapply(list(a=10,b=20), function(x){parent.frame()$i})
$a
[1] 2

$b
[1] 2

다른 이국적인 속임수들이 사용될 수 있습니다, 예를 들면,function(x){parent.frame()$i+0}또는function(x){--parent.frame()$i}.

성능 영향

강제 복제로 인해 성능이 저하됩니까?예! 다음은 벤치마크입니다.

> x <- as.list(seq_len(1e6))

> system.time( y <- lapply(x, function(x){parent.frame()$i[]}) )
user system elapsed
2.38 0.00 2.37
> system.time( y <- lapply(x, function(x){parent.frame()$i[]}) )
user system elapsed
2.45 0.00 2.45
> system.time( y <- lapply(x, function(x){parent.frame()$i[]}) )
user system elapsed
2.41 0.00 2.41
> y[[2]]
[1] 2

> system.time( y <- lapply(x, function(x){parent.frame()$i}) )
user system elapsed
1.92 0.00 1.93
> system.time( y <- lapply(x, function(x){parent.frame()$i}) )
user system elapsed
2.07 0.00 2.09
> system.time( y <- lapply(x, function(x){parent.frame()$i}) )
user system elapsed
1.89 0.00 1.89
> y[[2]]
[1] 1000000

결론

이 대답은 단지 당신이 이것을 사용하지 말아야 한다는 것을 보여줍니다...위의 Tommy와 같은 다른 솔루션을 찾는다면 코드를 더 쉽게 읽을 수 있을 뿐만 아니라 향후 릴리스와 더욱 호환될 수 있으므로 핵심 팀이 개발하려고 노력한 최적화 기능을 잃을 위험이 있습니다!


더 이상 작동하지 않는 이전 버전의 트릭:

> lapply(list(a=10,b=10,c=10), function(x)substitute(x)[[3]])

결과:

$a
[1] 1

$b
[1] 2

$c
[1] 3

설명:lapply .FUN(X[[1L]], ...),FUN(X[[2L]], ...)하는 인수는 입니다. 그래서 그것이 통과하는 주장은.X[[i]]i루프의 현재 인덱스입니다.평가하기 전에 이것을 얻으면 (즉, 사용할 경우)substitute), 되지 않은 됩니다.X[[i]]로 .[[수, 수인인 함수X및 (기호) 및i(정수).그렇게substitute(x)[[3]]정확하게 이 정수를 반환합니다.

인덱스가 있는 경우 다음과 같이 먼저 저장하면 이름에 간단하게 액세스할 수 있습니다.

L <- list(a=10,b=10,c=10)
n <- names(L)
lapply(L, function(x)n[substitute(x)[[3]]])

결과:

$a
[1] "a"

$b
[1] "b"

$c
[1] "c"

아니면 이 두 번째 속임수를 사용하는 것:-)

lapply(list(a=10,b=10,c=10), function(x)names(eval(sys.call(1)[[2]]))[substitute(x)[[3]]])

(결과는 동일합니다.)

2: 설명 2:sys.call(1)아온다를 합니다.lapply(...), 도록하록sys.call(1)[[2]]는 리트인사표현니다입식는용에 대한 입니다.lapply을 전달대에게 합니다.eval를 만듭니다.names액세스할 수 있습니다.까다롭지만, 효과가 있습니다.

보너스: 이름을 얻는 두 번째 방법:

lapply(list(a=10,b=10,c=10), function(x)eval.parent(quote(names(X)))[substitute(x)[[3]]])

:X는 의부 프유개다니체의 입니다.FUN 그고 의리인참다니조합수를의 합니다.lapply그래서 우리는 그것을 할 수 있습니다.eval.parent.

방법을했습니다...다른 방법을 사용하기 시작했습니다.사하는대를 사용하는 에.lapply사용하기 시작했습니다.mapply

n = names(mylist)
mapply(function(list.elem, names) { }, list.elem = mylist, names = n)

사해볼수있다니습용을 사용해 볼 .imap()purrr꾸러미

설명서에서 다음을 참조하십시오.

imap(x, ...)은 x에 이름이 있으면 map2(x, names(x), ...)의 단축형이고, 없으면 map2(x, seq_along(x), ...)입니다.

따라서 다음과 같이 사용할 수 있습니다.

library(purrr)
myList <- list(a=11,b=12,c=13) 
imap(myList, function(x, y) paste(x, y))

그러면 다음과 같은 결과를 얻을 수 있습니다.

$a
[1] "11 a"

$b
[1] "12 b"

$c
[1] "13 c"

그냥 이름을 입력하세요.

sapply(names(mylist), function(n) { 
    doSomething(mylist[[n]])
    cat(n, '\n')
}

토미의 대답은 명명된 벡터에 적용되지만 당신이 목록에 관심이 있다는 생각이 들었습니다.그리고 그는 호출 환경에서 "x"를 참조했기 때문에 엔드 어라운드를 하는 것처럼 보입니다.이 함수는 함수에 전달된 매개 변수만 사용하므로 전달된 개체의 이름에 대한 가정은 하지 않습니다.

x <- list(a=11,b=12,c=13)
lapply(x, function(z) { attributes(deparse(substitute(z)))$names  } )
#--------
$a
NULL

$b
NULL

$c
NULL
#--------
 names( lapply(x, function(z) { attributes(deparse(substitute(z)))$names  } ))
#[1] "a" "b" "c"
 what_is_my_name <- function(ZZZ) return(deparse(substitute(ZZZ)))
 what_is_my_name(X)
#[1] "X"
what_is_my_name(ZZZ=this)
#[1] "this"
 exists("this")
#[1] FALSE

제 대답은 토미와 캐러칼과 같은 방향으로 진행되지만 목록을 추가 개체로 저장할 필요는 없습니다.

lapply(seq(3), function(i, y=list(a=14,b=15,c=16)) { paste(names(y)[[i]], y[[i]]) })

결과:

[[1]]
[1] "a 14"

[[2]]
[1] "b 15"

[[3]]
[1] "c 16"

이렇게 하면 목록이 (적용하는 대신) FUN에 명명된 인수로 제공됩니다.lapply는 목록의 요소에 대해서만 반복하면 됩니다(목록의 길이를 변경할 때 이 첫 번째 인수를 lapply로 변경하도록 주의하십시오).

참고: 추가 인수로 적용할 목록을 직접 지정하는 것도 효과적입니다.

lapply(seq(3), function(i, y) { paste(names(y)[[i]], y[[i]]) }, y=list(a=14,b=15,c=16))

@둘 다 은 @caracals @Tommy의 예를 포함합니다.list그리고data.frame
r이다.listlist그리고data.frame의 (dput(r[[1]]마지막에).

names(r)
[1] "todos"  "random"
r[[1]][1]
$F0
$F0$rst1
   algo  rst  prec  rorac prPo pos
1  Mean 56.4 0.450 25.872 91.2 239
6  gbm1 41.8 0.438 22.595 77.4 239
4  GAM2 37.2 0.512 43.256 50.0 172
7  gbm2 36.8 0.422 18.039 85.4 239
11 ran2 35.0 0.442 23.810 61.5 239
2  nai1 29.8 0.544 52.281 33.1 172
5  GAM3 28.8 0.403 12.743 94.6 239
3  GAM1 21.8 0.405 13.374 68.2 239
10 ran1 19.4 0.406 13.566 59.8 239
9  svm2 14.0 0.385  7.692 76.2 239
8  svm1  0.8 0.359  0.471 71.1 239

$F0$rst5
   algo  rst  prec  rorac prPo pos
1  Mean 52.4 0.441 23.604 92.9 239
7  gbm2 46.4 0.440 23.200 83.7 239
6  gbm1 31.2 0.416 16.421 79.5 239
5  GAM3 28.8 0.403 12.743 94.6 239
4  GAM2 28.2 0.481 34.815 47.1 172
11 ran2 26.6 0.422 18.095 61.5 239
2  nai1 23.6 0.519 45.385 30.2 172
3  GAM1 20.6 0.398 11.381 75.7 239
9  svm2 14.4 0.386  8.182 73.6 239
10 ran1 14.0 0.390  9.091 64.4 239
8  svm1  6.2 0.370  3.584 72.4 239

목적은 다음과 같습니다.unlist모든 목록, 순서 입력list사건을 식별하기 위한 란으로서의 이름.

r=unlist(unlist(r,F),F)
names(r)
[1] "todos.F0.rst1"  "todos.F0.rst5"  "todos.T0.rst1"  "todos.T0.rst5"  "random.F0.rst1" "random.F0.rst5"
[7] "random.T0.rst1" "random.T0.rst5"

목록을 취소하지만 목록은 취소하지 않습니다.data.frame

ra=Reduce(rbind,Map(function(x,y) cbind(case=x,y),names(r),r))

Map이름 순서를 열로 표시합니다. Reducedata.frame

head(ra)
            case algo  rst  prec  rorac prPo pos
1  todos.F0.rst1 Mean 56.4 0.450 25.872 91.2 239
6  todos.F0.rst1 gbm1 41.8 0.438 22.595 77.4 239
4  todos.F0.rst1 GAM2 37.2 0.512 43.256 50.0 172
7  todos.F0.rst1 gbm2 36.8 0.422 18.039 85.4 239
11 todos.F0.rst1 ran2 35.0 0.442 23.810 61.5 239
2  todos.F0.rst1 nai1 29.8 0.544 52.281 33.1 172

추신.r[[1]]:

    structure(list(F0 = structure(list(rst1 = structure(list(algo = c("Mean", 
    "gbm1", "GAM2", "gbm2", "ran2", "nai1", "GAM3", "GAM1", "ran1", 
    "svm2", "svm1"), rst = c(56.4, 41.8, 37.2, 36.8, 35, 29.8, 28.8, 
    21.8, 19.4, 14, 0.8), prec = c(0.45, 0.438, 0.512, 0.422, 0.442, 
    0.544, 0.403, 0.405, 0.406, 0.385, 0.359), rorac = c(25.872, 
    22.595, 43.256, 18.039, 23.81, 52.281, 12.743, 13.374, 13.566, 
    7.692, 0.471), prPo = c(91.2, 77.4, 50, 85.4, 61.5, 33.1, 94.6, 
    68.2, 59.8, 76.2, 71.1), pos = c(239L, 239L, 172L, 239L, 239L, 
    172L, 239L, 239L, 239L, 239L, 239L)), .Names = c("algo", "rst", 
    "prec", "rorac", "prPo", "pos"), row.names = c(1L, 6L, 4L, 7L, 
    11L, 2L, 5L, 3L, 10L, 9L, 8L), class = "data.frame"), rst5 = structure(list(
        algo = c("Mean", "gbm2", "gbm1", "GAM3", "GAM2", "ran2", 
        "nai1", "GAM1", "svm2", "ran1", "svm1"), rst = c(52.4, 46.4, 
        31.2, 28.8, 28.2, 26.6, 23.6, 20.6, 14.4, 14, 6.2), prec = c(0.441, 
        0.44, 0.416, 0.403, 0.481, 0.422, 0.519, 0.398, 0.386, 0.39, 
        0.37), rorac = c(23.604, 23.2, 16.421, 12.743, 34.815, 18.095, 
        45.385, 11.381, 8.182, 9.091, 3.584), prPo = c(92.9, 83.7, 
        79.5, 94.6, 47.1, 61.5, 30.2, 75.7, 73.6, 64.4, 72.4), pos = c(239L, 
        239L, 239L, 239L, 172L, 239L, 172L, 239L, 239L, 239L, 239L
        )), .Names = c("algo", "rst", "prec", "rorac", "prPo", "pos"
    ), row.names = c(1L, 7L, 6L, 5L, 4L, 11L, 2L, 3L, 9L, 10L, 8L
    ), class = "data.frame")), .Names = c("rst1", "rst5")), T0 = structure(list(
        rst1 = structure(list(algo = c("Mean", "ran1", "GAM1", "GAM2", 
        "gbm1", "svm1", "nai1", "gbm2", "svm2", "ran2"), rst = c(22.6, 
        19.4, 13.6, 10.2, 9.6, 8, 5.6, 3.4, -0.4, -0.6), prec = c(0.478, 
        0.452, 0.5, 0.421, 0.423, 0.833, 0.429, 0.373, 0.355, 0.356
        ), rorac = c(33.731, 26.575, 40, 17.895, 18.462, 133.333, 
        20, 4.533, -0.526, -0.368), prPo = c(34.4, 52.1, 24.3, 40.7, 
        37.1, 3.1, 14.4, 53.6, 54.3, 116.4), pos = c(195L, 140L, 
        140L, 140L, 140L, 195L, 195L, 140L, 140L, 140L)), .Names = c("algo", 
        "rst", "prec", "rorac", "prPo", "pos"), row.names = c(1L, 
        9L, 3L, 4L, 5L, 7L, 2L, 6L, 8L, 10L), class = "data.frame"), 
        rst5 = structure(list(algo = c("gbm1", "ran1", "Mean", "GAM1", 
        "GAM2", "svm1", "nai1", "svm2", "gbm2", "ran2"), rst = c(17.6, 
        16.4, 15, 12.8, 9, 6.2, 5.8, -2.6, -3, -9.2), prec = c(0.466, 
        0.434, 0.435, 0.5, 0.41, 0.8, 0.44, 0.346, 0.345, 0.337), 
            rorac = c(30.345, 21.579, 21.739, 40, 14.754, 124, 23.2, 
            -3.21, -3.448, -5.542), prPo = c(41.4, 54.3, 35.4, 22.9, 
            43.6, 2.6, 12.8, 57.9, 62.1, 118.6), pos = c(140L, 140L, 
            195L, 140L, 140L, 195L, 195L, 140L, 140L, 140L)), .Names = c("algo", 
        "rst", "prec", "rorac", "prPo", "pos"), row.names = c(5L, 
        9L, 1L, 3L, 4L, 7L, 2L, 8L, 6L, 10L), class = "data.frame")), .Names = c("rst1", 
    "rst5"))), .Names = c("F0", "T0"))

각 원소의 길이를 계산하려고 합니다.

mylist <- list(a=1:4,b=2:9,c=10:20)
mylist

$a
[1] 1 2 3 4

$b
[1] 2 3 4 5 6 7 8 9

$c
 [1] 10 11 12 13 14 15 16 17 18 19 20

에 결과적인 요소들에 을 붙이는 이라면, 목이결요라붙것벨면이라이는을과,lapply(mylist,length)또는 그 이하의 작업.

sapply(mylist,length,USE.NAMES=T)

 a  b  c 
 4  8 11 

이라면, 함수내라사벨것는목이면라적이용하을부,mapply()목록 요소와 목록 이름의 두 개체를 루프하여 사용할 수 있습니다.

fun <- function(x,y) paste0(length(x),"_",y)
mapply(fun,mylist,names(mylist))

     a      b      c 
 "4_a"  "8_b" "11_c" 

@https-kraft는 우리에게 훌륭한 속임수를 주었고, 문서화되지 않았고 성능 오버헤드 때문에 사용하면 안 된다고 말합니다.

저는 첫 번째 점에 대해 크게 논쟁할 수는 없지만 간접비가 걱정되는 경우는 거의 없다는 점에 주목하고 싶습니다.

복잡한 표현을 부를 필요가 없도록 활성 함수를 정의합니다.parent.frame()$i[] 단지 만다..i()우리는 또한 만들 것입니다..n()기본 및 purr 기능(및 대부분의 다른 기능)에 모두 사용할 수 있는 이름에 액세스할 수 있습니다.

.i <- function() parent.frame(2)$i[]
# looks for X OR .x to handle base and purrr functionals
.n <- function() {
  env <- parent.frame(2)
  names(c(env$X,env$.x))[env$i[]]
}

sapply(cars, function(x) paste(.n(), .i()))
#>     speed      dist 
#> "speed 1"  "dist 2"

다른 함수를 (이 이다접이사인벡항붙에간함덱보벤여다니해습치수겠를크마한단벡있수제사다니여터화습할하용다을물음론른넣는스연은산목근터을법을용여하이▁nowations▁of▁canized▁whichthis,▁course▁using▁be▁to있▁oper▁a수▁vector다니습벡▁appro▁of▁vectoresaches▁different할화▁using터▁their이▁function▁simple▁(▁past▁let▁benchmark▁index제▁items▁a(▁the여하사s'용다을다보paste(vec, seq_along(vec))하지만 여기서 중요한 것은 그것이 아닙니다.)

벤치마킹 함수와 플로팅 함수를 정의하고 아래에 결과를 플롯합니다.

library(purrr)
library(ggplot2)
benchmark_fun <- function(n){
  vec <- sample(letters,n, replace = TRUE)
  mb <- microbenchmark::microbenchmark(unit="ms",
                                      lapply(vec, function(x)  paste(x, .i())),
                                      map(vec, function(x) paste(x, .i())),
                                      lapply(seq_along(vec), function(x)  paste(vec[[x]], x)),
                                      mapply(function(x,y) paste(x, y), vec, seq_along(vec), SIMPLIFY = FALSE),
                                      imap(vec, function(x,y)  paste(x, y)))
  cbind(summary(mb)[c("expr","mean")], n = n)
}

benchmark_plot <- function(data, title){
  ggplot(data, aes(n, mean, col = expr)) + 
    geom_line() +
    ylab("mean time in ms") +
    ggtitle(title) +
    theme(legend.position = "bottom",legend.direction = "vertical")
}

plot_data <- map_dfr(2^(0:15), benchmark_fun)
benchmark_plot(plot_data[plot_data$n <= 100,], "simplest call for low n")

benchmark_plot(plot_data,"simplest call for higher n")

reprex 패키지(v0.3.0)에 의해 2019-11-15에 생성되었습니다.

첫 번째 차트 시작 부분의 드롭은 요행입니다, 무시해 주세요.

우리는 선택된 답이 실제로 더 빠르다는 것을 알 수 있으며, 상당한 양의 반복 동안 우리의.i() 더. 는 션은정더느를 사용할 의 약 입니다. 선택한 답변과 비교했을 때 오버헤드는 사용할 때의 약 3배입니다.purrr::imap() 반복 시 약약합니다. 30,000회 반복당 약 1ms의 손실이 발생합니다. 30,000회 반복당 약 25ms의 손실은 1ms, 100회 반복당 1ms의 손실이 발생합니다.제 생각에는 편의상 적은 비용입니다.

만의 맞춤법을 .lapply를 수행

lapply2 <- function(X, FUN){
  if( length(formals(FUN)) == 1 ){
    # No index passed - use normal lapply
    R = lapply(X, FUN)
  }else{
    # Index passed
    R = lapply(seq_along(X), FUN=function(i){
      FUN(X[[i]], i)
    })
  }

  # Set names
  names(R) = names(X)
  return(R)
}

그런 다음 다음과 같이 사용합니다.

lapply2(letters, function(x, i) paste(x, i))

언급URL : https://stackoverflow.com/questions/9950144/access-lapply-index-names-inside-fun

반응형