Вычислить угол между каждыми 2 строками в кадре данных (каждая строка является вектором) в R? - PullRequest
0 голосов
/ 20 октября 2018

С учетом кадра данных гравитации:

df <- structure(list(user_id = c(1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 
1L), obs_id = c(1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L), scroll_id = c(1L, 
1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L), gra_x = c(-0.76694775, -0.7770001, 
-0.7770001, -0.7770001, -0.7864253, -0.7864253, -0.7864253, -0.7864253, 
-0.7947834, -0.80270606), gra_y = c(7.083949, 7.0901933, 7.0901933, 
7.0901933, 7.096873, 7.096873, 7.096873, 7.096873, 7.1042953, 
7.1121664), gra_z = c(6.737941, 6.730217, 6.730217, 6.730217, 
6.722077, 6.722077, 6.722077, 6.722077, 6.713248, 6.7039647)), .Names = c("user_id", 
"obs_id", "scroll_id", "gra_x", "gra_y", "gra_z"), row.names = c(NA, 
-10L), class = c("grouped_df", "tbl_df", "tbl", "data.frame"), vars = c("user_id", 
"obs_id", "scroll_id"), drop = TRUE, indices = list(0:9), group_sizes = 10L, biggest_group_size = 10L, labels = structure(list(
    user_id = 1L, obs_id = 1L, scroll_id = 1L), row.names = c(NA, 
-1L), class = "data.frame", vars = c("user_id", "obs_id", "scroll_id"
), drop = TRUE, .Names = c("user_id", "obs_id", "scroll_id")))

Я хочу вычислить угол между каждыми 2 векторами (gra_x, gra_y, gra_z)

, используя:

angle <- function(x,y){
    dot.prod <- x%*%y 
    norm.x <- norm(x,type="2")
    norm.y <- norm(y,type="2")
    theta <- acos(dot.prod / (norm.x * norm.y))
    as.numeric(theta)
  }

Я пыталсяиспользовать:

df %>% 
    select(gra_x, gra_y, gra_z) %>%
    mutate(theta = angle(c(gra_x, gra_y, gra_z), c(lead(gra_x), lead(gra_y), lead(gra_z))))

Но он возвращает ошибку.Посоветуйте, пожалуйста, как рассчитать угол между каждыми 2 рядами?

1 Ответ

0 голосов
/ 22 октября 2018

Я думаю, что это проще и, вероятно, эффективнее (без синтаксиса dplyr).См. [ R: по строкам dplyr :: mutate с использованием функции, которая берет строку фрейма данных и возвращает целое число и тесты.

Еще одна вещь, которую следует учитывать, это то, что acos иногда возвращает NaN.Решение предоставлено в (см. [ acos (1) возвращает NaN для некоторых значений, а не другие ) и используется в модифицированной функции angle() ниже.

angle <- function(x,y){
    dot.prod <- as.numeric(x%*%y )
    norm.x <- norm(x,type="2")
    norm.y <- norm(y,type="2")
    atheta<-dot.prod / (norm.x * norm.y)
    theta <- acos(pmin(pmax(atheta,-1.0),1.0))
    as.numeric(theta)
}

И мы можемпросто вычислите угол между каждыми 2 строками, используя цикл for:

df<-as.matrix(df)
df<-cbind(df, theta=NA)
for (i in 1:(nrow(df)-1)){
   df[i,"theta"]= angle(df[i,c("gra_x","gra_y","gra_z")] , df[i+1,c("gra_x","gra_y","gra_z")])
}

df
#      user_id obs_id scroll_id      gra_x    gra_y    gra_z       theta
# [1,]       1      1         1 -0.7669478 7.083949 6.737941 0.001441019
# [2,]       1      1         1 -0.7770001 7.090193 6.730217 0.000000000
# [3,]       1      1         1 -0.7770001 7.090193 6.730217 0.000000000
# [4,]       1      1         1 -0.7770001 7.090193 6.730217 0.001441059
# [5,]       1      1         1 -0.7864253 7.096873 6.722077 0.000000000
# [6,]       1      1         1 -0.7864253 7.096873 6.722077 0.000000000
# [7,]       1      1         1 -0.7864253 7.096873 6.722077 0.000000000
# [8,]       1      1         1 -0.7864253 7.096873 6.722077 0.001452513
# [9,]       1      1         1 -0.7947834 7.104295 6.713248 0.001480881
#[10,]       1      1         1 -0.8027061 7.112166 6.703965          NA
...