Методы упрощения данных во фрейме данных

#r #dataframe #row #simplify

#r #фрейм данных #строка #упрощение

Вопрос:

У меня есть набор из 15 фреймов данных, связанных с последовательностями белков, и моя цель — проанализировать изменения в белках с течением времени. Однако мои фреймы данных содержат около 5000 генов. Итак, я ищу способ упростить свои данные для упрощения анализа.

Ниже приведен пример фрейма данных.

 > sample
  p1 p2 p3 year
1  a  d  d 1970
2  a  c  e 1970
3  b  d  e 1970
4  b  c  d 1985
5  b  c  d 1985
6  b  c  d 1999
  

Что я хочу сделать, так это анализировать каждую позицию ( p1 p2 и p3 ) каждый год и возвращать наиболее распространенную запись в этой позиции в этом году и, таким образом, создавать новый фрейм данных только с одной последовательностью в год. Результирующий фрейм данных должен выглядеть как приведенный ниже пример:

 > result
  p1 p2 p3 year
1  a  d  e 1970
2  b  c  d 1985
3  b  c  d 1999
  

Фреймы данных уже отсортированы по дате, однако я не знаю, сколько записей в каждом году. Итак, есть ли способ упростить мои данные с помощью этого метода?

Ответ №1:

Решение data.table:

 dat <- read.table(text=' p1 p2 p3 year
1  a  d  d 1970
2  a  c  e 1970
3  b  d  e 1970
4  b  c  d 1985
5  b  c  d 1985
6  b  c  d 1999',header=TRUE)

library(data.table)
DT <- as.data.table(dat)

DT[,lapply(.SD,function(x){ y = table(x)
                            names(y)[which.max(y)]}),
   year]

#      year p1 p2 p3
#  1: 1970  a  d  e
#  2: 1985  b  c  d
#  3: 1999  b  c  d
  

ОТРЕДАКТИРУЙТЕ другое базовое решение R:

 do.call(rbind.data.frame,by(dat, dat$year, function(x) 
  lapply(x, function(y) { 
    t <- table(y)
    names(t)[which.max(t)]
  })))

#       p1 p2 p3 year
# 1970  a  d  e 1970
# 1985  b  c  d 1985
# 1999  b  c  d 1999
  

Ответ №2:

Используя только базовые функции R, вы можете решить эту проблему следующим образом.

 as.data.frame(t(
   sapply(split(sample, sample$year), function(x) {

      # for each x - data frame subset such grouped by year
      apply(x, 2, function(y) { 

          # for each y, i.e. column in x
          t <- table(y)
          names(t)[which.max(t)]  # return the label that occurs most often
      })

   })
))
  

Результат:

 ##      p1 p2 p3 year
## 1970  a  d  e 1970
## 1985  b  c  d 1985
## 1999  b  c  d 1999
  

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

1. 1 ! потому что все остальные решения — это просто переписывание этого. Я предлагаю использовать by для замены sapply split , избегать также apply , чтобы избежать принуждения к символам… смотрите мое базовое решение R выше.

2. Использование этой базовой функции выдало мне код ошибки, в котором говорилось In split.default(x = seq_len(nrow(x)), f = f, drop = drop, ...) : data length is not a multiple of split variable , что, однако, другая базовая операция R (от agstudy) работала отлично, поэтому я буду работать с ней…

Ответ №3:

Используя dplyr вы могли бы сделать это следующим образом:

 require(dplyr)

sample %>%
  group_by(year) %>%
  summarise_each(funs(names(which.max(table(.)))))
  

или

 sample %>%
  group_by(year) %>%
  summarise(p1 = names(which.max(table(p1))),
            p2 = names(which.max(table(p2))),
            p3 = names(which.max(table(p3))))
  

Результат в обоих случаях:

 #  year p1 p2 p3 
#1 1970  a  d  e
#2 1985  b  c  d
#3 1999  b  c  d
  

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

Редактировать

С помощью summarise_each вы также можете указать столбцы, которые вы либо не хотите включать в операцию, либо которые вы хотите включить (и исключить все остальные столбцы). Итак, представьте, что в вашем образце данных было 100 столбцов p1 … p100, и вы хотите сделать это для всех столбцов, кроме p1 и p3, вы могли бы указать:

 sample %>%
  group_by(year) %>%
  summarise_each(funs(names(which.max(table(.)))), -c(p1, p3))
  

С другой стороны, вы могли бы указать, чтобы это делалось только для этих двух столбцов:

 sample %>%
  group_by(year) %>%
  summarise_each(funs(names(which.max(table(.)))), p1, p3)
  

И вы можете добавить больше функций к funs аргументу внутри summarise_each .

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

1. 1 для использования summarise_each , стоит упомянуть, что вы также можете объединить его с фильтром, если хотите обработать все столбцы, кроме некоторых. Я все еще предпочитаю .SD здесь, он более гибкий 🙂

2. Спасибо за совет, фреймы данных, которые у меня есть, имеют разное количество столбцов (от 6 до 23), и я думаю, что в этом случае первый метод будет проще, поскольку я использую один код для всех фреймов данных