Wie wähle ich zwischen 3 Werten aus, wobei die 2 in R am nächsten beieinander liegen?

8

Ich möchte für jeden auswählen ID die beiden nächsten Werte vonCq . Ich dachte, ich hätte es herausgefunden, aber es hängt von der Reihenposition ab ...

Hier ist ein Beispiel für die Form meines Datensatzes:

df <- data.frame(ID = c("A","A","A","B","B","B","C","C","C"), 
                 Cq = c(34.32,34.40,34.31,31.49,31.40,31.49,31.22,31.31,31.08))
  ID    Cq
1  A 34.32
2  A 34.40
3  A 34.31
4  B 31.49
5  B 31.40
6  B 31.49
7  C 31.22
8  C 31.31
9  C 31.08

Und was ich versucht habe

df4 <-df %>% 
  group_by(ID) %>% 
  arrange(Cq) %>% 
  mutate(diffvals= Cq - lag(Cq)) %>%
  filter(row_number() == 1 | row_number() == 2)

#Output
ID       Cq   diffvals
1 A      34.31   NA     
2 A      34.32   0.0100
3 B      31.40   NA     
4 B      31.49   0.0900
5 C      31.08   NA     
6 C      31.22   0.14 

Und die erwartete Leistung

 ID    Cq
1  A 34.32
2  A 34.31
3  B 31.49
4  B 31.49
5  C 31.22
6  C 31.31

Ich habe bereits versucht, meinen Datensatz zu sortieren, aber er ändert nichts. Ich habe es auch versuchtfilter(diffvals=wich.min==diffvals) aber ich weiß nicht, wie ich die zwei kleinsten extrahieren soll.

Wenn Sie irgendwelche Ideen haben, würde es mir sehr helfen!

Danke im Voraus

user12933512
quelle

Antworten:

4

Hier ist ein Basis-R-Code, mit dem distdie Abstände aller Paare innerhalb von Gruppen aufgelistet werden, d. H.

dfout <- do.call(rbind,
                 lapply(split(df,df$ID), 
                        function(v) {
                          d <- `diag<-`(as.matrix(dist(v$Cq)),NA)
                          d[lower.tri(d)] <- NA
                          v[which(d==min(d,na.rm = T),arr.ind = T),]
                        }
                 ))

so dass

> dfout
    ID    Cq
A.1  A 34.32
A.3  A 34.31
B.4  B 31.49
B.6  B 31.49
C.7  C 31.22
C.8  C 31.31
ThomasIsCoding
quelle
3

Mit dplyreiner Option können Sie eine full_joinmit itselfbasierend auf tun ID. Entfernen Sie die Zeilen, die in Kombination mit sich selbst generiert werden, und IDwählen Sie für jede Zeile die Zeile mit dem minimalen Unterschied aus und erhalten Sie die Daten im Langformat.

library(dplyr)

df %>%
  mutate(Row = row_number()) %>%
  full_join(df, by = 'ID') %>%
  group_by(ID, Row) %>%
  filter(Cq.x != Cq.y) %>%
  group_by(ID) %>%
  slice(which.min(abs(Cq.x - Cq.y))) %>%
  tidyr::pivot_longer(cols  = starts_with('Cq')) %>%
  select(-Row, -name)

#  ID    value
#  <fct> <dbl>
#1 A      34.3
#2 A      34.3
#3 B      31.5
#4 B      31.4
#5 C      31.2
#6 C      31.3
Ronak Shah
quelle
1

Versuche dies:

library(tidyverse)
df <- data.frame(ID = c("A","A","A","B","B","B","C","C","C"), 
                 Cq = c(34.32,34.40,34.31,31.49,31.40,31.49,31.22,31.31,31.08))

df_summ <- 
  df %>% 
  group_by(ID) %>% 
  arrange(Cq) %>% 
  mutate(
    prev = lag(Cq),
    diff= Cq - lag(Cq)) %>% 
  drop_na()
df_summ %>% 
  group_by(ID) %>% 
  summarise(diff = min(diff)) %>% 
  left_join(df_summ) %>% 
  select(-diff) %>% 
  pivot_longer(c(Cq, prev), values_to = "cq") %>% 
  select(-name)

Grüße Paweł

Pawel Stradowski
quelle
1

In der Basis R.

do.call(rbind, lapply(split(df, df$ID), function(x){ 
  cell <- order(abs(outer(x$Cq, x$Cq, `-`)))[-seq(nrow(x))][1] - 1;
  x[c((cell %/% nrow(x)) + 1, (cell %% nrow(x)) + 1),]}))
#>     ID    Cq
#> A.1  A 34.32
#> A.3  A 34.31
#> B.4  B 31.49
#> B.6  B 31.49
#> C.7  C 31.22
#> C.8  C 31.31
Allan Cameron
quelle
0

Unterschiedliche Ausgabe, aber funktional gleichwertig

do.call(rbind,
  by(df,list(df$ID),function(x){
    tmp=abs(outer(x$Cq,x$Cq,"-"))
    tmp[upper.tri(tmp,diag=T)]=Inf
    x$Cq[which(tmp==min(tmp),arr.ind=T)]
  })
)

   [,1]  [,2]
A 34.31 34.32
B 31.49 31.49
C 31.31 31.22
user2974951
quelle