#r
#r
Вопрос:
У меня есть этот набор данных:
Alt;- c(10,20,10,31,51,1,60,1,02,0,12,0,20,1,0,0,0,0,1,0,1,1,1) Blt;- c(1,0,0,1,1,1,0,1,1,0,1,1,0,0,0,1,0,0,0,0,0,0,0) Clt;- c(1,0,0,1,1,1,0,1,1,0,1,1,0,0,0,1,0,0,0,0,0,0,1) SUB lt;- c(1,1,1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,2,2,2,2) dat lt;- as.data.frame(cbind(SUB,B,A,C))
Я написал функцию, вычисляющую cor среди A/B, B/C, C/A.
Z lt;- function(a,b,c) { cor1 = cor(a,b) cor2 = cor(b,c) cor3 = cor(c,a) x = c(cor1,cor2,cor3) return(x) }
если я наберу
Z(dat$A, dat$B,dat$C)
Я получаю вектор результатов:
gt; [1] 0.11294312 0.91417410 0.06457059
Мне нужно привязать свою функцию к переменной SUB и получить матрицу, строки которой являются одинаковыми среди A/B, B/C, C/A для каждой подстановки.
Например:
A/B B/C C/A SUB1 0.11294312 0.91417410 0.06457059 SUB2 0.10335312 0.96744677 0.16356059
Спасибо, с наилучшими пожеланиями
Комментарии:
1. К вашему сведению, обычно плохая практика называть переменные или функции после базовых функций/примитивов R;
try
обычно используется другими пакетами/функциями в форме защитного программирования. В то время как R, как правило, подходит для определения того, что использовать в каждом контексте, устранение неполадок, основанных на этом, будет значительно разочаровывать.2. Пожалуйста, будьте осторожны с образцами данных;
C
это длина 22, все остальные-длина 23. R перерабатывает a1
в 23-ю позицию, не уверен, что это проблема для вас (хотя это почти наверняка изменит корреляции).3. Спасибо, я все исправил.
4. @r2evans Я полностью не согласен с утверждением, что это плохая практика. Наоборот: столкновения имен в реальном коде неизбежны, и перепрыгивание через обручи, чтобы заинтересовать их, приводит к запутанным, многословным именам, которые в конечном итоге затрудняют чтение кода. Тем не менее, это,
try
в частности, редко подходящее название. Программисты должны вместо этого использовать пространства имен, что является проверенным и верным способом решения этой проблемы. R к сожалению, это не поощряется, но пакет «коробка» облегчает определение имен.5. Я не согласен с советом использовать пространства имен, но … сколько раз вы помогали кому-то, кто непреднамеренно использовал неправильную функцию/объект? R не всегда наиболее откровенен с полезными сообщениями об ошибках в этом отношении, по крайней мере, для неопытного пользователя R. Как более опытный разработчик, мне удобно называть свои переменные произвольно (в том числе так же, как примитивы/функции), но новые пользователи R, как правило, не распознают знаки. Как бы то ни было, это субъективно. (И да, «соглашения об именах»- одна из двух самых сложных вещей в CS: -)
Ответ №1:
основание R
Вы можете разделиться, by
а затем рекомбинировать.
do.call(rbind, by(dat, dat$SUB, function(x) Z(x$A, x$B, x$C))) # [,1] [,2] [,3] # 1 -0.1534126 1.0000000 -0.15341258 # 2 0.1081781 0.8215838 0.04608456
Имена строк 1
и 2
сами SUB
значения; если SUB
это более «интересно», чем подсчет чисел, это будет более очевидно. Имена столбцов можно применять тривиально.
dplyr
library(dplyr) dat %gt;% group_by(SUB) %gt;% summarize(as.data.frame(matrix(Z(A, B, C), nr = 1))) # # A tibble: 2 x 4 # SUB V1 V2 V3 # lt;dblgt; lt;dblgt; lt;dblgt; lt;dblgt; # 1 1 -0.153 1.00 -0.153 # 2 2 0.108 0.822 0.0461
Ответ №2:
Попробуйте split
в сочетании с sapply
sapply( split(dat,dat$SUB), function(x) Z(x["A"],x["B"],x["C"]) ) 1 2 [1,] -0.1534126 0.10817808 [2,] 1.0000000 0.82158384 [3,] -0.1534126 0.04608456
Ответ №3:
На самом деле в вашей функции нет необходимости, если вы используете матрицу upper.tri
cor
отношений. В последнее время вы можете сделать это очень легко, проложив трубопровод:
sapply(unique(dat$SUB), (i) cor(dat[dat$SUB == i, -1]) |gt; {(x) x[upper.tri(x)]}()) # [,1] [,2] # [1,] -0.1534126 0.10817808 # [2,] 1.0000000 0.82158384 # [3,] -0.1534126 0.04608456 R.version.string # [1] "R version 4.1.2 (2021-11-01)"
Данные
dat lt;- structure(list(SUB = c(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2), B = c(1, 0, 0, 1, 1, 1, 0, 1, 1, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0), A = c(10, 20, 10, 31, 51, 1, 60, 1, 2, 0, 12, 0, 20, 1, 0, 0, 0, 0, 1, 0, 1, 1, 1), C = c(1, 0, 0, 1, 1, 1, 0, 1, 1, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1)), class = "data.frame", row.names = c(NA, -23L ))
Ответ №4:
Это длинный ответ, но он должен быть довольно гибким.
library(tidyverse) cor.by.group.combos lt;- function(.data, groups, vars){ by lt;- gsub(x = rlang::quo_get_expr(enquo(groups)), pattern = "\((.*)?\)", replacement = "\1")[-1] piv lt;- gsub(x = rlang::quo_get_expr(enquo(vars)), pattern = "\((.*)?\)", replacement = "\1")[-1] .data %gt;% group_by(!!!groups) %gt;% group_split() %gt;% map(., ~pivot_longer(., cols = all_of(piv), names_to = "name", values_to = "val") %gt;% nest(data = val) %gt;% full_join(.,.,by = by) %gt;% filter(name.x != name.y) %gt;% mutate(test = paste(name.x, "vs",name.y, sep = "."), grp = paste0(by,!!!groups), cor = map2_dbl(data.x,data.y, ~cor(unlist(.x), unlist(.y)))) %gt;% select(test,grp, cor) ) %gt;% bind_rows() %gt;% pivot_wider(names_from = test, values_from = cor) } cor.by.group.combos(dat, vars(SUB), vars(A, B, C)) #gt; # A tibble: 2 x 7 #gt; grp A.vs.B A.vs.C B.vs.A B.vs.C C.vs.A C.vs.B #gt; lt;chrgt; lt;dblgt; lt;dblgt; lt;dblgt; lt;dblgt; lt;dblgt; lt;dblgt; #gt; 1 SUB1 -0.153 -0.153 -0.153 1 -0.153 1 #gt; 2 SUB2 0.108 0.0461 0.108 0.822 0.0461 0.822
По сути, то, что мы делаем, — это разбивка данных по группам, а затем применение cor
теста к каждой комбинации выбранных переменных. То, как я это настрою, даст некоторые повторяющиеся тесты (например, A. против B и B. против A). Вы могли бы исправить это , используя combn
вместо full_join
этого, но я не стал тратить время на проработку деталей. Эта функция должна работать, если вы изменяете входные переменные, группирующие переменные и т. Д. Вы также можете применить несколько групп с помощью этого метода.