Изменить форму фрейма данных и рассмотреть 1, если 0 и 1 присутствует - PullRequest
0 голосов
/ 26 января 2019

У меня есть фрейм данных, который содержит 500 строк и 20000 столбцов. строки содержат разные идентификаторы выборки и имеют одинаковые идентификаторы выборки в строках, но разные значения столбцов. Мой фрейм данных такой .....

sample_name   E002.c1   E004.c1  E005.c1  E007.c1  so on...
T4456-C        0           0        0        0
T4456-C        1           0        0        1
T4456-C        1           0        1        1
T9589-C        0           1        0        0
T9589-C        1           1        0        0

Есть ли способ объединить эти идентификаторы как

Если столбец содержит 0 для всех, тогда рассматривайте значение как 0 Если столбец содержит хотя бы одну единицу, то считается значение 1.

Ожидаемый результат: -

sample_name   E002.c1   E004.c1  E005.c1  E007.c1  so on...
T4456-C        1           0        1        1
T9589-C        1           1        0        0

Ответы [ 3 ]

0 голосов
/ 26 января 2019

Также возможна tidyverse:

df %>%
 group_by(sample_name) %>%
 summarise_all(funs(ifelse(any(. == 1), 1, 0)))

  sample_name E002.c1 E004.c1 E005.c1 E007.c1
  <fct>         <dbl>   <dbl>   <dbl>   <dbl>
1 T4456-C          1.      0.      1.      1.
2 T9589-C          1.      1.      0.      0.

Группируется по "sample_name" и затем проверяет, есть ли какое-либо значение == 1. Если это так, он присваивает 1, в противном случае 0.

Или то же самое с data.table:

setDT(df)[, lapply(.SD, function(x) ifelse(any(x == 1), 1, 0)), by = sample_name]

   sample_name E002.c1 E004.c1 E005.c1 E007.c1
1:     T4456-C       1       0       1       1
2:     T9589-C       1       1       0       0

Или только с основанием R:

aggregate(. ~ sample_name, data = df, function(x) ifelse(any(x == 1), 1, 0))

  sample_name E002.c1 E004.c1 E005.c1 E007.c1
1     T4456-C       1       0       1       1
2     T9589-C       1       1       0       0

Или группировка по «sample_name», а затем суммирование максимального значения, предложенного @R Yoda:

df %>%
 group_by(sample_name) %>%
 summarise_all(funs(max))

То же самое с data.table:

setDT(df)[, lapply(.SD, max), by = sample_name]

и с основанием R:

aggregate(. ~ sample_name, data = df, max)

Или используя числовое деление:

df %>%
 group_by(sample_name) %>%
 summarise_all(funs(any(. %/% 1 == 1)*1))

То же самое с data.table:

setDT(df)[, lapply(.SD, function(x) any(x %/% 1 == 1)*1), by = sample_name]

И база R:

aggregate(. ~ sample_name, data = df, function(x) any(x %/% 1 == 1)*1)
0 голосов
/ 26 января 2019

Опция base R с использованием aggregate и использованием унарного оператора +

aggregate(. ~ sample_name, data = df, function(x) +(sum(x) > 0))
#  sample_name E002.c1 E004.c1 E005.c1 E007.c1
#1     T4456-C       1       0       1       1
#2     T9589-C       1       1       0       0

Это позволяет избежать каких-либо явных условий ifelse.


Пример данных

df <- read.table(text =
    "sample_name   E002.c1   E004.c1  E005.c1  E007.c1
T4456-C        0           0        0        0
T4456-C        1           0        0        1
T4456-C        1           0        1        1
T9589-C        0           1        0        0
T9589-C        1           1        0        0", header = T)

Анализ микробенчмарков

Ниже приведены результаты microbenchmark анализа всех методов, представленных в этом посте, с использованием большего набора данных, состоящего из N=10^6 строк:

# Generate sample with 10^6 rows
N <- 10^6
df <- data.frame(
    sample_name = sample(letters[1:10], N, replace = T),
    col1 = sample(c(1, 0), N, replace = T),
    col2 = sample(c(1, 0), N, replace = T),
    col3 = sample(c(1, 0), N, replace = T),
    col4 = sample(c(1, 0), N, replace = T))

# Microbenchmark analysis
library(microbenchmark)
res <- microbenchmark(
    tidyverse_ifelse_any = {
        df %>% group_by(sample_name) %>% summarise_all(funs(ifelse(any(. == 1), 1, 0)))
    },
    tidyverse_max = {
        df %>% group_by(sample_name) %>% summarise_all(funs(max))
    },
    tidyverse_any_int_div = {
        df %>% group_by(sample_name) %>% summarise_all(funs(any(. %/% 1 == 1)*1))
    },
    tidyverse_mutate_if_ifelse = {
        df %>% group_by(sample_name) %>% summarise_all(sum) %>% mutate_if(is.numeric, funs(if_else(. > 0, 1, 0)))
    },
    baseR_ifelse_any = {
        aggregate(. ~ sample_name, data = df, function(x) ifelse(any(x == 1), 1, 0))
    },
    baseR_max = {
        aggregate(. ~ sample_name, data = df, max)
    },
    baseR_any_int_div = {
        aggregate(. ~ sample_name, data = df, function(x) any(x %/% 1 == 1)*1)
    },
    baseR_sum_unary_plus = {
        aggregate(. ~ sample_name, data = df, function(x) +(sum(x) > 0))
    },
    datatable_ifelse_any = {
        setDT(df)[, lapply(.SD, function(x) ifelse(any(x == 1), 1, 0)), by = sample_name]
    },
    datatable_any_int_div = {
        setDT(df)[, lapply(.SD, function(x) any(x %/% 1 == 1)*1), by = sample_name]
    }
)

res
#Unit: milliseconds
#                       expr        min         lq       mean     median
#       tidyverse_ifelse_any   79.54145   87.49671  101.44983   96.69517
#              tidyverse_max   60.85648   66.54888   75.71105   70.26009
#      tidyverse_any_int_div  130.17937  139.99099  158.74449  152.59370
# tidyverse_mutate_if_ifelse   60.63313   66.42935   75.17535   70.19083
#           baseR_ifelse_any  933.11576 1070.73916 1157.92271 1121.52533
#                  baseR_max  895.94086 1046.37304 1121.74497 1097.73445
#          baseR_any_int_div 1003.90893 1115.72278 1179.91529 1138.17459
#       baseR_sum_unary_plus  903.09797 1049.83542 1127.51391 1099.56222
#       datatable_ifelse_any   93.47955   97.21338  111.67774  100.98314
#      datatable_any_int_div  157.81882  164.51094  179.08096  173.94033
#         uq       max neval    cld
#  109.08000  259.4346   100 ab
#   80.39179  142.4100   100 a
#  166.56710  349.8669   100   c
#   76.91358  253.4256   100 a
# 1187.60461 1775.9125   100     ef
# 1167.16448 1544.4371   100    d
# 1218.67363 1592.0093   100      f
# 1196.53435 1375.8022   100    de
#  115.57745  282.7197   100  b
#  187.37031  317.1613   100   c

library(ggplot2)
autoplot(res)

Если я не ошибся, я удивлен, что

  1. решения base R значительно медленнее, чем решения tidyverse / data.table (в конце концов, код tidyverse обычно не о эффективном коде, а о чистом коде), и
  2. решения data.table не намного быстрее, чем решения tidyverse / base R.

enter image description here

0 голосов
/ 26 января 2019

Попробуйте это:

library(tidyverse)

df %>%
  group_by(sample_name) %>%
  summarise_all(sum) %>%
  mutate_if(is.numeric, funs(if_else(. > 0, 1, 0)))
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...