Средство строк на основе подстроки столбца - PullRequest
5 голосов
/ 15 марта 2020

У меня есть кадр данных, который выглядит следующим образом:

df <- data.frame("CB_1.1"=c(0,5,6,2), "CB_1.16"=c(1,5,3,6), "HC_2.11"=c(3,3,4,5), "HC_1.12"=c(2,3,4,5), "HC_1.13"=c(1,0,0,5))

> df
  CB_1.1 CB_1.16 HC_2.11 HC_1.12 HC_1.13
1      0       1       3       2       1
2      5       5       3       3       0
3      6       3       4       4       0
4      2       6       5       5       5

Я хотел бы взять среднее значение строк, которые разделяют подстроку имени столбца, перед ".". В результате получается такой кадр данных:

  CB_1 HC_2 HC_1
1  0.5    3  1.5
2  5.0    3  1.5
3  4.5    4  2.0
4  4.0    5  5.0

Вы заметите, что значения столбца HC_2.11 остаются прежними, потому что ни один другой столбец не имеет HC_2 в этом кадре данных.

Буду признателен за любую помощь!

Ответы [ 4 ]

4 голосов
/ 15 марта 2020

1) apply / tapply Для каждой строки используйте tapply, используя ИНДЕКС префиксов имени и функцию mean. Транспонировать результат. Пакеты не используются.

prefix <- sub("\\..*", "", names(df))
t(apply(df, 1, tapply, prefix, mean))

с этой матрицей (оберните ее в data.frame (...), если вам нужен результат фрейма данных):

     CB_1 HC_1 HC_2
[1,]  0.5  1.5    3
[2,]  5.0  1.5    3
[3,]  4.5  2.0    4
[4,]  4.0  5.0    5

2) lm Запустите указанную регрессию. +0 в формуле означает, что не добавляет перехват. Транспонирование коэффициентов будет требуемой матрицей m. В следующей строке сделайте имена лучше. prefix из (1). Пакеты не используются.

m <- t(coef(lm(t(df) ~ prefix + 0)))
colnames(m) <- sub("prefix", "", colnames(m))
m

с этой матрицей

     CB_1 HC_1 HC_2
[1,]  0.5  1.5    3
[2,]  5.0  1.5    3
[3,]  4.5  2.0    4
[4,]  4.0  5.0    5

Это следует из того факта, что (1) матрица модели X содержит только единицы и нули и (2) отдельные столбцы из этого ортогональны. Здесь показана матрица модели:

X <- model.matrix(~ prefix + 0) # model matrix
X

, что дает:

  prefixCB_1 prefixHC_1 prefixHC_2
1          1          0          0
2          1          0          0
3          0          0          1
4          0          1          0
5          0          1          0
attr(,"assign")
[1] 1 1 1
attr(,"contrasts")
attr(,"contrasts")$prefix
[1] "contr.treatment"

Поскольку столбцы матрицы модели X ортогональны коэффициенту, соответствующему любому столбцу для конкретной строки, y, из df (столбец t(df)) просто sum(x * y) / sum(x * x), а поскольку x - это вектор 0/1, который равен среднему значению значений y, соответствующих единицам в x.

3) stack / tapply Преобразовать в длинную форму, вставив столбец id одновременно. Затем используйте tapply, чтобы преобразовать обратно в широкоформатную форму mean. Пакеты не используются.

long <- transform(stack(df), ind = sub("\\..*", "", ind), id = c(row(df)))    
with(long, tapply(values, long[c("id", "ind")], mean))

с указанием этой таблицы. Оберните его в as.data.frame.matrix, если вы хотите data.frame.

   ind
id  CB_1 HC_1 HC_2
  1  0.5  1.5    3
  2  5.0  1.5    3
  3  4.5  2.0    4
  4  4.0  5.0    5
3 голосов
/ 15 марта 2020
  • Вот базовое решение R с использованием rowMeans + split.default, то есть
dfout <- as.data.frame(Map(rowMeans, split.default(df,factor(s <- gsub("\\..*$","",names(df)), levels = unique(s)))))

, такое что

> dfout
  CB_1 HC_2 HC_1
1  0.5    3  1.5
2  5.0    3  1.5
3  4.5    4  2.0
4  4.0    5  5.0
  • Если вы не возражаете против порядка имен столбцов, вы можете использовать более короткий код ниже
dfout <- as.data.frame(Map(rowMeans,split.default(df,gsub("\\..*$","",names(df)))))

такой, что

> dfout
  CB_1 HC_1 HC_2
1  0.5  1.5    3
2  5.0  1.5    3
3  4.5  2.0    4
4  4.0  5.0    5
1 голос
/ 15 марта 2020

Базовая опция может быть:

#find column names splitting on "."

cols <- unique(sapply(strsplit(names(df),".", fixed = T), `[`, 1))

#loop through each column name and find the rowMeans

as.data.frame(sapply(cols, function (x) rowMeans(df[grep(x, names(df))])))

  CB_1 HC_2 HC_1
1  0.5    3  1.5
2  5.0    3  1.5
3  4.5    4  2.0
4  4.0    5  5.0
1 голос
/ 15 марта 2020

Один вариант, включающий dplyr и purrr, может быть:

map_dfc(.x = unique(sub("\\..*$", "", names(df))),
        ~ df %>%
         transmute(!!.x := rowMeans(select(., starts_with(.x)))))

  CB_1 HC_2 HC_1
1  0.5    3  1.5
2  5.0    3  1.5
3  4.5    4  2.0
4  4.0    5  5.0
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...