Как рассчитать список углов между двумя линейными векторами в серии образцов в R? - PullRequest
0 голосов
/ 19 февраля 2020

Я работаю над геометрией c Морфометрия c Набор данных биологических образцов с двумерными декартовыми координатами (т.е. ориентирами). Часть моего интереса к этому набору данных состоит в том, чтобы создать кадр данных о расстояниях между важными ориентирами и углами между векторами ориентиров с гомологичными координатами по всем образцам для дальнейшего сравнения. Расстояния между точками не были проблемой, но у меня возникали проблемы, когда я пытался вычислить углы в каждом из моих образцов.

Я пытаюсь найти способ вычислить угол между линейными векторами, представляющими один и тот же угол на серии образцов одновременно (векторы описывают особенность с биологической значимостью, которая присутствует во всех образцах в моем наборе данных). Пакет R, который я использую для управления данными морфометрии c, выводит ориентиры как трехмерный объект класса array(), где строки - это ориентиры, столбцы - это размеры координаты, а третье измерение - это образец. Вот координаты ориентира для трех образцов в данных образца, представленных здесь.

, , Specimen1

         X         Y
1  -0.2411  0.060183
2  -0.0677 -0.029954
3   0.1147  0.012111
4   0.0085  0.000462

, , Specimen2

          X       Y
1  -0.22509  0.0764
2  -0.09437 -0.0202
3   0.09135 -0.0182
4   0.00367 -0.0045

, , Specimen3

         X        Y
1  -0.2223  0.06122
2  -0.1001 -0.02366
3   0.0553  0.00577
4  -0.0617 -0.01557

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

data<-array(data=c(-0.2411,-0.0677,0.1147,0.0085,0.060183,-0.029954,0.012111,0.000462,-0.22509,-0.09437,0.09135,0.00367,0.0764,-0.0202,-0.0182,-0.0045,-0.2223,-0.1001,0.0553,-0.0617,0.06122,-0.02366,0.00577,-0.01557),c(4,2,3))

Мне интересно найти угол, образованный линиями между точками 1 и 2 и точками 3 и 4. Для этого я вычисляю вектор этих двух линий, вычитая координаты одной точки из другой. Когда я это делаю, я получаю матрицу 2 * N для каждого вектора, где строки соответствуют векторам по осям X и Y, а столбцы соответствуют образцу.

Я хочу найти угол между этими двумя векторами для образца 1 (столбец 1 на обеих матрицах), 2, 3 и т. д. В идеале я хотел бы получить выходные данные в формате, где R сообщает угол для каждого отдельного образца, например так:

     Angle1
[,1] 146
[,2] 152
[,3] 135

И затем каким-то образом добавить его в кадр данных, чтобы он выглядел так:

          Distance Angle1 Angle2
Specimen1 100      146    100
Specimen2 100      152    100
Specimen3 100      135    100

Расстояния и значения для Angle2 являются просто числами заполнения, чтобы показать формат, которого я пытаюсь достичь.

Я пытался использовать функцию angle() в mathlib * Пакет 1022 * и функция angle.calc() в пакете Morpho . Вот код, который я использовал для вычисления угла с помощью функции angle().

vector1<-data[1,,]-data[2,,]
vector2<-data[3,,]-data[4,,]
angle(as.vector(vector1),as.vector(vector2),degree=TRUE)

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

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

Ответы [ 2 ]

2 голосов
/ 19 февраля 2020

Прежде всего, немного сложно дать матрице 2x3 имя vector1. Кроме того, вы можете использовать matlib::angle для вычисления углов.

library(matlib)
phi <- setNames(mapply(
    function(x1, x2) angle(x1, x2),
    as.data.frame(vector1), as.data.frame(vector2)),
    paste0("Specimen", 1:ncol(vector1)))
phi
#Specimen1 Specimen2 Specimen3
# 146.2674  152.4439  134.8753

Объяснение: Используйте mapply для одновременной итерации по столбцам vector1 и vector2, которые были преобразованы в data.frame с. Используйте stack для преобразования именованного вектора в data.frame:

stack(phi)
#    values       ind
#1 146.2674 Specimen1
#2 152.4439 Specimen2
#3 134.8753 Specimen3
0 голосов
/ 19 февраля 2020

В общем, вам может быть проще сначала получить ваши данные в длинном / аккуратном формате. Это позволяет упростить группировку и агрегацию, в которых векторизованные / отображенные операции могут действительно сиять.

Вот один из способов сделать это с предоставленными вами данными:

library(matlib)
library(tidyverse)

n_specimen <- ncol(vector1)

data.frame(t(vector1)) %>%
  rename_all(~str_replace(., "X", "v1_")) %>%
  bind_cols(
    data.frame(t(vector2)) %>%
      rename_all(~str_replace(., "X", "v2_"))
    ) %>%
  mutate(specimen = paste0("Specimen", 1:n_specimen)) %>%
  pivot_longer(-specimen, names_to = "vector", values_to = "value") %>%
  separate(vector, into = c("vector", "ix"), sep = "_", remove = TRUE) %>%
  group_by(specimen) %>%
  summarise(angle = angle(value[vector == "v1"], value[vector == "v2"])) 

  specimen  angle
  <chr>     <dbl>
1 Specimen1  146.
2 Specimen2  152.
3 Specimen3  135.

В порядке пояснения вот как выглядит фрейм данных после шага separate:

# A tibble: 12 x 4
   specimen  vector ix      value
   <chr>     <chr>  <chr>   <dbl>
 1 Specimen1 v1     1     -0.173 
 2 Specimen1 v1     2      0.0901
 3 Specimen1 v2     1      0.106 
 4 Specimen1 v2     2      0.0116
 5 Specimen2 v1     1     -0.131 
 6 Specimen2 v1     2      0.0966
 7 Specimen2 v2     1      0.0877
 8 Specimen2 v2     2     -0.0137
 9 Specimen3 v1     1     -0.122 
10 Specimen3 v1     2      0.0849
11 Specimen3 v2     1      0.117 
12 Specimen3 v2     2      0.0213

Каждый столбец имеет уникальный уровень информации, и теперь вы можете группировать и суммировать до требуемого уровня специфичности.

...