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

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

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

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ł


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

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
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.