Разделить значения матрицы по категориям означает в R

#r #matrix #categories #transformation

#r #матрица #Категории #преобразование

Вопрос:

У меня есть матрица (A), содержащая 211 строк и 6 столбцов (по одному за период времени), и другая матрица (B), содержащая 211 строк и 2 столбца, вторая из которых содержит категориальную информацию (1-9).

Моя цель — создать новую матрицу (C), где каждое значение в матрице A представляет собой значение (A), деленное на среднее значение (значение (A) по категории (B)). Мне удалось вычислить средние значения для каждой категории для каждого столбца с помощью агрегатной функции. Они хранятся в отдельном фрейме данных column_means, причем каждая временная волна находится в отдельном столбце. Это также содержит информацию о группе в column_means[,1] .

Я не понимаю, как действовать дальше, и ищу элегантное решение, чтобы я мог перенести эти знания в будущие проекты (и, возможно, улучшить свой существующий код). Я предполагаю, что решение скрыто где-то в dplyr и довольно просто, как только вы это узнаете.

Спасибо за любые предложения.

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

 ##each column here represents a wave:
initialmatrix <- structure(c(0.882647671948723, 0.847932241438909, 0.753052308699317, 
0.754977233408875, NA, 0.886095543329695, 0.849625252682829, 
0.78893884364632, 0.77111113840682, NA, 0.887255207679895, 0.851503493865384, 
0.812107856411831, 0.793982699495818, NA, 0.885212452552841, 
0.854894065774315, 0.815265718290737, 0.806766276556325, NA, 
0.882027335190646, 0.85386634818439, 0.818052477777012, 0.815997781565393, 
NA, 0.88245957310107, 0.855819521951304, 0.830425687228663, 0.820857689847061, 
NA), .Dim = 5:6, .Dimnames = list(NULL, c("V1", "V2", "V3", "V4", 
"V5", "V6")))

##the first column is unique ID, the 2nd the category:
categories <- structure(c(1L, 2L, 3L, 4L, 5L, 2L, 1L, 2L, 2L, 4L), .Dim = c(5L, 
2L), .Dimnames = list(NULL, c("V1", "V2")))

##the first column represents the category, column 1-6 the mean per category for each corresponding wave in "initialmatrix"
column.means <- structure(list(Group.1 = 1:5, x = c(0.805689153058216, 0.815006230419524, 
0.832326976776262, 0.794835253329865, 0.773041961434791), asset_means_2...2. = c(0.80050960343197, 
0.81923553710203, 0.833814773618545, 0.797834687980729, 0.780028077018158
), asset_means_3...2. = c(0.805053341257357, 0.828691564900149, 
0.833953165695685, 0.799381078569563, 0.785813047374534), asset_means_4...2. = c(0.806116664276125, 
0.832439754757116, 0.835982197159582, 0.801702200401293, 0.788814840753852
), asset_means_5...2. = c(0.807668548993891, 0.83801834926905, 
0.836036508152776, 0.803433961863399, 0.79014026195926), asset_means_6...2. = c(0.808800359101212, 
0.840923947682599, 0.839660313992458, 0.804901773257962, 0.793165113115977
)), row.names = c(NA, 5L), class = "data.frame")
  

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

1. Можете ли вы добавить минимальный пример (данные, код, который вы пробовали и т. Д.), Чтобы сделать вашу проблему воспроизводимой?

2. Конечно, Маркус — извините, я думал, что проблема достаточно проста, но, оглядываясь назад, воспроизводимые примеры всегда являются более разумным выбором. Как я уже сказал, я не знаю, как действовать дальше — я с трудом могу найти способ начать решение проблемы, поэтому мне придется разочаровать вас в отношении кода, который я пробовал до сих пор, хотя я все еще занимаюсь исследованиями, пока мы говорим.

3. Есть ли у вас причина использовать матрицы вместо фреймов данных? Кажется, что если бы вы начали с одного фрейма данных из 7 столбцов, это можно было бы легко решить с помощью dplyr.

4. Я открыт для решения с использованием df и dplyr, Ламия — конечно! Я просто преобразовываю их обратно сразу после. Причина, по которой я использую матрицы, заключается в том, что библиотека, которую я использую (RSiena), требует, чтобы формат матрицы считывался в ковариатах.

5. Если я правильно понимаю, у вас есть 3 категории: 1,2 и 4. Так, например, для категории 2, которая имеет 3 строки, что вы хотите, чтобы нормализовать значение (0.8826477) в col 1 строка 1 в A by? Другими словами, каков ваш ожидаемый результат?

Ответ №1:

Это то, что вы пытаетесь сделать?

 options(digits=3)
divisor <- column.means[categories[, 2], -1]
divisor
#         x asset_means_2...2. asset_means_3...2. asset_means_4...2. asset_means_5...2. asset_means_6...2.
# 2   0.815              0.819              0.829              0.832              0.838              0.841
# 1   0.806              0.801              0.805              0.806              0.808              0.809
# 2.1 0.815              0.819              0.829              0.832              0.838              0.841
# 2.2 0.815              0.819              0.829              0.832              0.838              0.841
# 4   0.795              0.798              0.799              0.802              0.803              0.805
initialmatrix/divisor
#         x asset_means_2...2. asset_means_3...2. asset_means_4...2. asset_means_5...2. asset_means_6...2.
# 2   1.083              1.082              1.071              1.063              1.053              1.049
# 1   1.052              1.061              1.058              1.061              1.057              1.058
# 2.1 0.924              0.963              0.980              0.979              0.976              0.988
# 2.2 0.926              0.941              0.958              0.969              0.974              0.976
# 4      NA                 NA                 NA                 NA                 NA                 NA
  

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

1. Спасибо — это сработало безупречно. Пока я использую это решение.

Ответ №2:

Это похоже на работу для Superma … нет, подождите … map2 .

 library(dplyr)
library(purrr)

as_tibble(initialmatrix) %>%
  mutate(category = as.double(as_tibble(categories)$V2),
         across(starts_with('V'), 
                ~ unlist(map2(., category, ~ .x/mean(c(.x, .y)))))) %>%
  select(-category)

#       V1     V2     V3     V4     V5     V6
#    <dbl>  <dbl>  <dbl>  <dbl>  <dbl>  <dbl>
# 1  0.612  0.614  0.615  0.614  0.612  0.612
# 2  0.918  0.919  0.920  0.922  0.921  0.922
# 3  0.547  0.566  0.578  0.579  0.581  0.587
# 4  0.548  0.557  0.568  0.575  0.580  0.582
# 5  NA     NA     NA     NA     NA     NA    
  

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

1. Спасибо, rjen. К сожалению, я получаю следующую ошибку: `Ошибка: проблема с mutate() вводом ..2 . x отображенные векторы должны иметь согласованную длину: * .x имеет длину 211 * .y имеет длину 422 ℹ Ввод ..2 across(...) . Теперь, очевидно, 422 в два раза больше, чем 211, поэтому я предполагаю, что это умножает категории * на количество столбцов (2)? Также спасибо за предложение функции map2. Удобный материал, я вчитываюсь в него.

2. @SteffenT: Добро пожаловать. Мое решение работает для меня последовательно, когда я использую данные примера. 1) Работает ли мое решение с примерами данных на вашем конце? 2) Если да, я думаю, нам следует искать расхождения между вашими данными и данными примера, которые вы предоставили.

3. Это работает с примером, так что действительно, должны быть расхождения. ответ dcarlsons (выше) сработал для меня, поэтому я оставлю это на этом, но буду читать в map2, когда столкнусь с другими подобными проблемами. Еще раз спасибо!