большой датафрейм: «повторный» t-тест между группами для тысячи факторов - PullRequest
0 голосов
/ 13 мая 2018

Я прочитал много постов, связанных с обработкой данных и «повторным» t-тестом, но я не могу понять, как добиться этого в моем случае.

Вы можете получить мой пример набора данных для StackOverflow здесь: https://www.dropbox.com/s/0b618fs1jjnuzbg/dataset.example.stckovflw.txt?dl=0

У меня есть большой массив данных выражения gen, такой как:

> b<-read.delim("dataset.example.stckovflw.txt")

> head(b)
      animal            gen condition tissue    LogFC
1 animalcontrol1         kjhss1   control  brain 7.129283
2 animalcontrol1          sdth2   control  brain 7.179909
3 animalcontrol1     sgdhstjh20   control  brain 9.353147
4 animalcontrol1 jdygfjgdkydg21   control  brain 6.459432
5 animalcontrol1  shfjdfyjydg22   control  brain 9.372865
6 animalcontrol1      jdyjkdg23   control  brain 9.541097

> str(b)
'data.frame':   21507 obs. of  5 variables:
 $ animal   : Factor w/ 25 levels "animalcontrol1",..: 1 1 1 1 1 1 1 1 1 1 ...
 $ gen      : Factor w/ 1131 levels "dghwg1041","dghwg1086",..: 480 761 787    360 863 385 133 888 563 738 ...
 $ condition: Factor w/ 5 levels "control","treatmentA",..: 1 1 1 1 1 1 1 1 1 1 ...
 $ tissue   : Factor w/ 2 levels "brain","heart": 1 1 1 1 1 1 1 1 1 1 ...
 $ LogFC    : num  7.13 7.18 9.35 6.46 9.37 ...

В каждой группе 5 животных,и у каждого животного есть много количественных генов.(Тем не менее, каждое животное может иметь различный набор количественных генов, но также многие из генов будут общими для животных и групп).

Я хотел бы выполнить t-тест для каждого поколения между моей группой (A, B, C или D) и контрольной группой.Данные должны быть представлены в виде таблицы, содержащей p-значение для каждого гена в каждой группе.

Поскольку у меня столько генов (тысяч), я не могу подгруппировать каждый ген.

У васзнаете, как я могу автоматизировать процедуру?

Я думал о цикле, но я абсолютно не уверен, что он может достичь того, что я хочу, и как продолжить.

Кроме того, я посмотрел больше на эти посты, используя функцию apply: Применение t-критерия ко многим столбцам в кадре данных, разделенных на коэффициенты и Циклическая проверка t.testsдля подмножеств фрейма данных в r

# ################ дополнительная информация после прочтения первых комментариев и ответов:

@ andrew_reece: Большое спасибо за это,Это почти то, что я искал.Однако я не могу найти способ сделать это с помощью t-критерия.ANOVA - это интересная информация, но тогда мне нужно будет узнать, какая из обработанных групп значительно отличается от моей контрольной группы.Также мне нужно было бы знать, какая из обработанных групп значительно отличается друг от друга, «два на два».

Я пытался использовать ваш код, изменив «aov (..)» в «t.тестовое задание(…)".Для этого сначала я реализую подмножество (b, условие == "контроль" | условие == "обработка A"), чтобы сравнить только две группы.Однако при экспорте таблицы результатов в CSV-файл эта таблица недоступна для понимания (без имени поколения, без значений p и т. Д., Только числа).Я буду продолжать искать способ сделать это правильно, но до сих пор я застрял.

@ 42:

Большое спасибо за эти советы.Это просто пример набора данных, давайте предположим, что нам нужно использовать отдельные t-тесты.

Это очень полезное начало для изучения моих данных.Например, я пытался представить свои данные с помощью Venndiagrams.Я могу написать свой код, но это отчасти из начальной темы.Кроме того, я не знаю, как суммировать менее придирчивый общий ген, обнаруженный в каждой комбинации условий, поэтому я упростил только 3 условия.

# Visualisation of shared genes by VennDiagrams :
# let's simplify and consider only 3 conditions :

b<-read.delim("dataset.example.stckovflw.txt")
b<- subset(b, condition == "control" | condition == "treatmentA" | condition == "treatmentB")

b1<-table(b$gen, b$condition)

b1

b2<-subset(data.frame(b1, "control" > 2 
              |"treatmentA" > 2 
              |"treatmentB" > 2 ))

b3<-subset(b2, Freq>2) # select only genes that have been quantified in at     least 2 animals per group
b3
b4 = within(b3, {
  Freq = ifelse(Freq > 1, 1, 0)
}) # for those observations, we consider the gene has been detected so we     change the value 0 regardless the freq of occurence (>2)


b4

b5<-table(b4$Var1, b4$Var2)
write.csv(b5, file = "b5.csv")

# make an intermediate file .txt (just add manually the name of the cfirst     column title)
# so now we have info
bb5<-read.delim("bb5.txt")

nrow(subset(bb5, control == 1))
nrow(subset(bb5, treatmentA == 1))
nrow(subset(bb5, treatmentB == 1))

nrow(subset(bb5, control == 1 & treatmentA == 1))
nrow(subset(bb5, control == 1 & treatmentB == 1))
nrow(subset(bb5, treatmentA == 1 & treatmentB == 1))

nrow(subset(bb5, control == 1 & treatmentA == 1 & treatmentB == 1))

library(grid)
library(futile.logger)
library(VennDiagram)

venn.plot <- draw.triple.venn(area1 = 1005, 
                          area2 = 927, 
                          area3 = 943, 
                          n12 = 843, 
                          n23 = 861, 
                          n13 = 866, 
                          n123 = 794, 
                          category = c("controls", "treatmentA",     "treatmentB"),  
                          fill = c("red", "yellow", "blue"),
                          cex = 2,
                          cat.cex = 2,
                          lwd = 6,
                          lty = 'dashed',
                          fontface = "bold",
                          fontfamily = "sans",
                          cat.fontface = "bold",
                          cat.default.pos = "outer",
                          cat.pos = c(-27, 27, 135),
                          cat.dist = c(0.055, 0.055, 0.085),
                          cat.fontfamily = "sans",
                          rotation = 1);

enter image description here

Ответы [ 2 ]

0 голосов
/ 13 мая 2018

Обновление (за комментарии OP):
Парным сравнением по condition можно управлять с помощью специального теста ANOVA, такого как «Честная достоверная разница Тьюки» (stats::TukeyHSD()). (Есть и другие, это всего лишь один из способов продемонстрировать PoC.)

results <- b %>%
  mutate(condition = factor(condition)) %>%
  group_by(gen) %>%
  filter(length(unique(condition)) >= 2) %>%
  nest() %>%
  mutate(
    model = map(data, ~ TukeyHSD(aov(LogFC ~ condition, data = .x))),
    coef = map(model, ~ broom::tidy(.x))
  ) %>%
  unnest(coef) %>% 
  select(-term)

    results
# A tibble: 7,118 x 6
   gen        comparison            estimate conf.low conf.high adj.p.value
   <chr>      <chr>                    <dbl>    <dbl>     <dbl>       <dbl>
 1 kjhss1     treatmentA-control       1.58     -20.3      23.5       0.997
 2 kjhss1     treatmentC-control      -3.71     -25.6      18.2       0.962
 3 kjhss1     treatmentD-control       0.240    -21.7      22.2       1.000
 4 kjhss1     treatmentC-treatmentA   -5.29     -27.2      16.6       0.899
 5 kjhss1     treatmentD-treatmentA   -1.34     -23.3      20.6       0.998
 6 kjhss1     treatmentD-treatmentC    3.95     -18.0      25.9       0.954
 7 sdth2      treatmentC-control      -1.02     -21.7      19.7       0.991
 8 sdth2      treatmentD-control       3.25     -17.5      24.0       0.909
 9 sdth2      treatmentD-treatmentC    4.27     -16.5      25.0       0.849
10 sgdhstjh20 treatmentC-control      -7.48     -30.4      15.5       0.669
# ... with 7,108 more rows

Оригинальный ответ
Вы можете использовать tidyr::nest() и purrr::map(), чтобы выполнить техническую задачу группировки по gen, а затем проводить статистические тесты, сравнивая эффекты condition (предположительно с LogFC как твой DV).

Но я согласен с другими комментариями о том, что здесь есть проблемы с вашим статистическим подходом, которые заслуживают внимательного рассмотрения - stats.stackexchange.com является лучшим форумом для этих вопросов.

В целях демонстрации я использовал ANOVA вместо t-критерия, поскольку на группу gen часто приходится более двух условий. Однако это не должно изменить интуицию, стоящую за реализацией.

require(tidyverse)

results <- b %>%
  mutate(condition = factor(condition)) %>%
  group_by(gen) %>%
  filter(length(unique(condition)) >= 2) %>%
  nest() %>%
  mutate(
    model = map(data, ~ aov(LogFC ~ condition, data = .x)),
    coef = map(model, ~ broom::tidy(.x))
  ) %>%
  unnest(coef) 

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

results %>%
  filter(term!="Residuals") %>%
  select(gen, df, statistic, p.value)

results
# A tibble: 1,111 x 4
   gen               df statistic p.value
   <chr>          <dbl>     <dbl>   <dbl>
 1 kjhss1            3.     0.175   0.912
 2 sdth2             2.     0.165   0.850
 3 sgdhstjh20        2.     0.440   0.654
 4 jdygfjgdkydg21    2.     0.267   0.770
 5 shfjdfyjydg22     2.     0.632   0.548
 6 jdyjkdg23         2.     0.792   0.477
 7 fckjhghw24        2.     0.790   0.478
 8 shsnv25           2.     1.15    0.354
 9 qeifyvj26         2.     0.588   0.573
10 qsiubx27          2.     1.14    0.359
# ... with 1,101 more rows

Примечание: я не могу много доверять этому подходу - он взят почти дословно из примера, который я видел, как Хэдли выступала вчера вечером на лекции purrr. Вот ссылка на публичный репозиторий демонстрационного кода, который он использовал, который охватывает аналогичный вариант использования.

0 голосов
/ 13 мая 2018

У вас есть 25 животных в 5 разных группах лечения с различным количеством генов (предположительно, активностью генетических зондов) в двух разных тканях:

table(b$animal, b$condition)

                    control treatmentA treatmentB treatmentC treatmentD
  animalcontrol1       1005          0          0          0          0
  animalcontrol2        857          0          0          0          0
  animalcontrol3        959          0          0          0          0
  animalcontrol4        928          0          0          0          0
  animalcontrol5       1005          0          0          0          0
  animaltreatmentA1       0        927          0          0          0
  animaltreatmentA2       0        883          0          0          0
  animaltreatmentA3       0        908          0          0          0
  animaltreatmentA4       0        861          0          0          0
  animaltreatmentA5       0        927          0          0          0
  animaltreatmentB1       0          0        943          0          0
  animaltreatmentB2       0          0        841          0          0
  animaltreatmentB3       0          0        943          0          0
  animaltreatmentB4       0          0        910          0          0
  animaltreatmentB5       0          0        943          0          0
  animaltreatmentC1       0          0          0        742          0
  animaltreatmentC2       0          0          0        724          0
  animaltreatmentC3       0          0          0        702          0
  animaltreatmentC4       0          0          0        698          0
  animaltreatmentC5       0          0          0        742          0
  animaltreatmentD1       0          0          0          0        844
  animaltreatmentD2       0          0          0          0        776
  animaltreatmentD3       0          0          0          0        812
  animaltreatmentD4       0          0          0          0        783
  animaltreatmentD5       0          0          0          0        844

Согласитесь, вам нужно «автоматизировать» это вв некотором роде, но я думаю, что вам нужна более общая стратегия для статистического вывода, а не пытаться выявить отношения, применяя отдельные t-тесты.Вы можете рассмотреть либо смешанные модели, либо один из вариантов случайного леса.Я думаю, вы должны обсудить это со статистиком.В качестве примера того, где ваши надежды не оправдаются, взгляните на имеющуюся у вас информацию о первом «гене» среди 1131 значения:

str( b[ b$gen == "dghwg1041", ])
'data.frame':   13 obs. of  5 variables:
 $ animal   : Factor w/ 25 levels "animalcontrol1",..: 1 6 11 2 7 12 3 8 13 14 ...
 $ gen      : Factor w/ 1131 levels "dghwg1041","dghwg1086",..: 1 1 1 1 1 1 1 1 1 1 ...
 $ condition: Factor w/ 5 levels "control","treatmentA",..: 1 2 3 1 2 3 1 2 3 3 ...
 $ tissue   : Factor w/ 2 levels "brain","heart": 1 1 1 1 1 1 1 1 1 1 ...
 $ LogFC    : num  4.34 2.98 4.44 3.87 2.65 ...

У вас есть справедливое число с "полное представление:

gen_length <- ave(b$LogFC, b$gen, FUN=length)
Hmisc::describe(gen_length)
#--------------
gen_length 
       n  missing distinct     Info     Mean      Gmd      .05      .10 
   21507        0       18    0.976    20.32    4.802       13       14 
     .25      .50      .75      .90      .95 
      18       20       24       25       25 

Value          5     8     9    10    12    13    14    15    16    17
Frequency    100    48   288   270    84   624   924  2220    64   527
Proportion 0.005 0.002 0.013 0.013 0.004 0.029 0.043 0.103 0.003 0.025

Value         18    19    20    21    22    23    24    25
Frequency    666  2223  3840    42   220  1058  3384  4925
Proportion 0.031 0.103 0.179 0.002 0.010 0.049 0.157 0.229

Вы можете начать с просмотра всех "генералов", которые имеют полные данные:

head( gen_tbl[ gen_tbl == 25 ], 25)
#------------------
   dghwg1131     dghwg546     dghwg591     dghwg636     dghwg681 
          25           25           25           25           25 
    dghwg726    dgkuck196    dgkuck286    dgkuck421    dgkuck691 
          25           25           25           25           25 
   dgkuck736 dgkukdgse197 dgkukdgse287 dgkukdgse422 dgkukdgse692 
          25           25           25           25           25 
dgkukdgse737       djh592       djh637       djh682       djh727 
          25           25           25           25           25 
   dkgkjd327    dkgkjd642    dkgkjd687    dkgkjd732  fckjhghw204 
          25           25           25           25           25 
...