Mam listę etykiet związanych z wartościami. Chciałbym, aby uzyskać wartość x, aby znaleźć etykietę odpowiadającą najbliższej (ale gorszej) wartości listy.

Znalazłem sposób na to, ale wygląda dość bałagan i skomplikowane ...

mylist <- list("A"=0.02,
               "B"=0.13,
               "C"=0.26)

x = 0.14 # B

df <- as.data.frame(t(as.data.frame(mylist)))
df <- tibble::rownames_to_column(df, "labels")
df$V2 <- x > df$V1
maxi <- max(df[df$V2 == TRUE,]$V1)
label <- df[df$V1 == maxi,]$labels

Czy jest inny, schludny sposób robienia tego?

1
Dominique Makowski 4 czerwiec 2018, 10:50

4 odpowiedzi

Najlepsza odpowiedź

Odejmujemy wartość x z każdą wartością mylist, filtrować te, w których różnica jest większa niż 0 i wybierz names minimalnej różnicy.

new <- x - unlist(mylist) 
names(which.min(new[new > 0]))
#[1] "B"

Lub jeden -liner, gdzie filtrujemy tylko te wartości, które są mniejsze niż x i wybierz z niego max.

names(which.max(sapply(mylist, function(i) i[(x - i) > 0])))
#[1] "B"
1
Ronak Shah 4 czerwiec 2018, 08:05

Twoja lista powinna być Vector:

myvector <- c("A"=0.02,
              "B"=0.13,
              "C"=0.26)
#sort
myvector <- sort(myvector, decreasing = TRUE)
#test
test <- x > myvector
#name of element with first TRUE in test
res <- if(any(test)) names(which.max(test)) else NA_character_
#[1] "B"
0
Roland 4 czerwiec 2018, 07:58

Możesz sortować wektor, a następnie weź poprzednią wartość:

a=sort(c(x=x,unlist(mylist)))
names(a[which(names(a)=="x")-1])
[1] "B"
0
Onyambu 4 czerwiec 2018, 08:20

Polecam inne bardziej kompaktowe rozwiązania, ale oto schludna wersja tego, co próbowałeś osiągnąć:

library(tidyverse)
mylist %>%
  as_tibble %>%
  gather %>%
  filter(value < x) %>%
  summarize(key=key[which.max(value)]) %>%
  pull(key)

# [1] "B"
0
Moody_Mudskipper 4 czerwiec 2018, 08:20