Как обрезать процент точек данных в определенном диапазоне в R

#r #random #bioinformatics

Вопрос:

У меня есть текстовый файл, содержащий миллионы значений p (диапазон: 1-5e — 09, ($P)). Моя цель состоит в том, чтобы сгенерировать график Манхэттена в R, используя эти p-значения. Однако, поскольку подавляющее большинство значений p находятся в диапазоне 0,01-1, я хотел бы случайным образом обрезать, скажем, 95% значений p в этом диапазоне перед созданием графика (чтобы уменьшить размер выходного файла). До сих пор я использовал:

 data <- read.table(<path_to_my_p-value_file>)
data <- subset(data,data$P<=0.01)
 

но эта команда удаляет все значения p, превышающие 0,01, что приводит к появлению неприглядного разрыва между осью x и оставшимися значениями p на графике Манхэттена. Есть ли способ обрезать большинство значений p в указанном диапазоне (вместо всех)?

Комментарии:

1. (1) При использовании subset(data, ...) нет причин использовать data$ в вызове , просто используйте subset(data, P <= 0.01) . Это относится не ко всем функциям, но subset и все dplyr:: функции ценят «нестандартную оценку». (2) Было бы намного проще, если бы вы могли сгенерировать приемлемый образец набора данных (это не обязательно должны быть фактические значения p), чтобы продемонстрировать, с чего вы начинаете и что вы намереваетесь. Спасибо.

Ответ №1:

Здесь метод, который обнуляет 90% самых высоких 95% значений. Очевидно, что вы не хотели бы делать это на оригинале ваших данных, а скорее на копии, из которой вы затем удалили бы 0. Умножьте более высокие значения p (самые высокие 95% в этом примере) на случайную выборку из {,0,1} правильной длины с вероятностью 0,9 для 0 и 0,1 для 1

  set.seed(123)
 dx <- data.frame(x=runif(100))
 dx$sel <- dx$x < 0.05    #Should "select" the lowest 5%, leave them alone
 dx$x[!dx$sel] <- dx$x[!dx$sel]*   # only work on the higher ones
                       sample(c(0,1),size=sum(!dx$sel), replace=TRUE, prob=c(.9,.1))
 

Возвращает вам пять значений ниже 0,05 и 11 выше 0,05. Точное количество этих более высоких значений будет немного отличаться в зависимости от случайного начального значения и длины построенного вектора.

 > table(dx$x)

                   0 0.000624773325398564   0.0246136845089495   0.0420595335308462 
                  84                    1                    1                    1 
  0.0455564993899316   0.0458311666734517   0.0935949867125601    0.102924682665616 
                   1                    1                    1                    1 
   0.320373242488131    0.414546335814521    0.453334156190977    0.511505459900945 
                   1                    1                    1                    1 
    0.59414202044718    0.656758127966896    0.883017404004931    0.892419044394046 
                   1                    1                    1                    1 
   0.954503649147227 
 

Вы также можете посмотреть на код, используемый функциями, которые выполняют «winsorizing». (Нет, я не ошибся в написании этого термина.)

Ответ №2:

Это кажется немного хакерским, но следующее может это сделать. В основном он сначала проверяет наличие условия (здесь, если x > 0), а затем заменяет отсутствующий процент значений на основе > runif() (здесь .95). После этого вы можете удалить строки с отсутствующими значениями.

Однако должен быть лучший способ достижения желаемых результатов…

 df2 <- df %>% mutate(
  x = if_else(condition = x > 0,
              true = if_else(runif(length(x))<.95, NA_real_, x),
              false = x
  )
)
 

репрекс

 library(dplyr)

set.seed(42)
n <- 300
df <- data.frame(
  x = rnorm(n), 
  y = rnorm(n)
)

df2 <- df %>% mutate(
  x = if_else(condition = x > 0,
              true = if_else(runif(length(x))<.95, NA_real_, x),
              false = x
  )
)
plot(df, pch = 3)
points(df2, col = "red")
 

Создано 2021-07-05 пакетом reprex (v2.0.0)