Расчет смещения частиц в реальном времени: проблемы с ifelse, в условном цикле for - PullRequest
0 голосов
/ 15 января 2020

Будучи все еще довольно новым для R, я борюсь со следующей проблемой: я смотрю на несколько частиц, движущихся вдоль оси x (в действительности это в 3D, но это упрощает вопросы для нашей цели, здесь). У меня есть фрейм данных с идентификатором каждой частицы и их соответствующим положением в данный момент времени. Вот пример:

x.position1 <- c(5, NA, 4, 7, 1, NA, 2, NA, NA, 3)
x.position2 <- c(6, NA, 8, 7, 2, 1, 2, NA, NA, 1)
x.position3 <- c(6, 2, 7, 7, 4, 3, 1, NA, NA, 6)
x.position4 <- c(7, 4, 9, 7, 5, 5, 0, 0, 5, 7)
x.position5 <- c(9, 5, NA, 7, 6, NA, 2, 3, 8, 11)
particule.ID <- c(1:10)
df <- data.frame(particule.ID, x.position1, x.position2, x.position3, x.position4, x.position5)
df

   particule.ID x.position1 x.position2 x.position3 x.position4 x.position5
1             1           5           6           6           7           9
2             2          NA          NA           2           4           5
3             3           4           8           7           9          NA
4             4           7           7           7           7           7
5             5           1           2           4           5           6
6             6          NA           1           3           5          NA
7             7           2           2           1           0           2
8             8          NA          NA          NA           0           3
9             9          NA          NA          NA           5           8
10           10           3           1           6           7          11

Моя цель - рассчитать смещение каждой частицы в каждый момент времени i. Следовательно, это смещение xi - x1. Это недавно вычисленное смещение должно быть помещено во вновь созданный столбец.

Вот сценарий, который я первоначально написал для этого:

for (i in 1:5){ # iterate for each time point i
  df$Disp <- df[,2+i-1]-df[,2] # create a new column with the calculated displacement for time point i
  nam.Disp <- paste("Disp", i, sep = "") #rename new column Disp+time point number
  names(df)[names(df) == 'Disp'] <- nam.Disp
}

df

particule.ID x.position1 x.position2 x.position3 x.position4 x.position5 Disp1 Disp2 Disp3 Disp4 Disp5
1             1           5           6           6           7           9     0     1     1     2     4
2             2          NA          NA           2           4           5    NA    NA    NA    NA    NA
3             3           4           8           7           9          NA     0     4     3     5    NA
4             4           7           7           7           7           7     0     0     0     0     0
5             5           1           2           4           5           6     0     1     3     4     5
6             6          NA           1           3           5          NA    NA    NA    NA    NA    NA
7             7           2           2           1           0           2     0     0    -1    -2     0
8             8          NA          NA          NA           0           3    NA    NA    NA    NA    NA
9             9          NA          NA          NA           5           8    NA    NA    NA    NA    NA
10           10           3           1           6           7          11     0    -2     3     4     8


Однако, как вы можете заметить во фрейме данных, иногда частица не обнаружена при i = 1 или позже. Это означает, что я получаю значение NA. Следовательно, включая еще один l oop с IF, чтобы, если эта 1-я точка времени была NA, R переместилась бы go к следующей временной точке, пока не найдет значение не NA для вычитания. Поэтому я придумал это, используя ifelse вместо IF, поскольку последнее может иметь дело только с одним значением, в то время как мой ввод фактически является столбцом:

for (i in 1:5){ # iterate for each time point i
  for (j in 1:5){ # if first time point has no value (NA) scan the row for next time point until an object is detected
    ifelse(!is.na(df[,2+j-1]),
           df$Disp <- (df[,2+i-1]-df[,2+j-1]), # create a new column with the calculated displacement for i time point
           next) # if time point is NA go to next j (next fixed initial time point to test)
  }
  nam.Disp <- paste("Disp", i, sep = "") #rename new column Disp+time point number
  names(df)[names(df) == 'Disp'] <- nam.Disp

}

df

   particule.ID x.position1 x.position2 x.position3 x.position4 x.position5 Disp1 Disp2 Disp3 Disp4 Disp5
1             1           5           6           6           7           9    -4    -3    -3    -2     0
2             2          NA          NA           2           4           5    NA    NA    -3    -1     0
3             3           4           8           7           9          NA    NA    NA    NA    NA    NA
4             4           7           7           7           7           7     0     0     0     0     0
5             5           1           2           4           5           6    -5    -4    -2    -1     0
6             6          NA           1           3           5          NA    NA    NA    NA    NA    NA
7             7           2           2           1           0           2     0     0    -1    -2     0
8             8          NA          NA          NA           0           3    NA    NA    NA    -3     0
9             9          NA          NA          NA           5           8    NA    NA    NA    -3     0
10           10           3           1           6           7          11    -8   -10    -5    -4     0

Каким-то образом это возвращает неправильные значения. Похоже, что вычисления произошли в обратном направлении: Disp1 = x5-x1, Disp2 = x5-x2, Disp3 = x5-x3 et c ... в то время как я ожидал: Disp1 = x1-x1, Disp2 = x2-x1, Disp3 = x3-x1 et c. Как это могло вызвать включение нового для l oop и функции ifelse? Что я делаю неправильно? Возможно, есть способ сделать это вручную, но, поскольку на самом деле у меня есть как минимум 60 временных моментов, если не больше, задача будет сложной.

Кроме того, если вы считаете, что есть гораздо более умный способ сделать это Пожалуйста, поделитесь! И если я забуду включить важные детали, которые помогут вам лучше понять, просто дайте мне знать.

Большое спасибо!

Flo

Ответы [ 2 ]

1 голос
/ 15 января 2020

Поскольку вы хотите вычислить разницу определенного времени i от времени 1 для каждой позиции, вы получите NA, если одно из двух чисел равно NA.

В вашем случае мы можем создать второй фрейм данных df2, который фиксирует изменения от времени 1 до i для каждой позиции 1 до 10.

df2<-data.frame(matrix(NA, nrow = 10, ncol = 4)) 

colnames(df2)<-cbind("chp2","chp3","chp4","chp5")

Мы можем зафиксировать различия в al oop:

for (i in 1:4) { for (j in 1:10) {
  df2[i][j,]<-df[i+2][j,]-df[2][j,] 
} 

}

Теперь мы можем поместить их все во фрейм данных, если хотим df1<-cbind(df,df2)

1 голос
/ 15 января 2020

Пример того, как решить вашу проблему в длинном формате:

library(data.table)
library(zoo)
library(stringr)

df <- setDT(df)
dflong <- melt(df,patterns = "position",id.vars = "particule.ID",value.name = "position")
dflong[,time := str_extract(variable,"[0-9]+$")]  
setkey(dflong,time)
dflong[,displacement := c(NA,diff(na.locf(position,na.rm = F))),by = particule.ID]


    particule.ID    variable position time displacement
 1:            1 x.position1        5    1           NA
 2:            1 x.position2        6    2            1
 3:            1 x.position3        6    3            0
 4:            1 x.position4        7    4            1
 5:            1 x.position5        9    5            2
 6:            2 x.position1       NA    1           NA
 7:            2 x.position2       NA    2           NA
 8:            2 x.position3        2    3           NA
 9:            2 x.position4        4    4            2
10:            2 x.position5        5    5            1
11:            3 x.position1        4    1           NA
12:            3 x.position2        8    2            4
13:            3 x.position3        7    3           -1
14:            3 x.position4        9    4            2
15:            3 x.position5       NA    5            0
.....

Я использую здесь data.table, но то же самое можно сделать с dplyr и tidyr, с pivot_long.

 melt(df,patterns = "position",id.vars = "particule.ID",value.name = "position")

преобразуйте ваши данные в длинный формат, используя 3 переменные: имя столбца, содержащее время, идентификатор частицы и положение.

Затем я извлекаю время с помощью str_extract из stringr:

dflong[,time := str_extract(variable,"[0-9]+$")]  

Я упорядочиваю таблицу по ID и времени setkey(dflong,time)

Затем я использую diff(position) для каждого particule.ID для расчета смещения. Но так как я знаю, что у меня проблемы с Nas, я использую na.locf из zoo, что позволяет мне заменить NA последним доступным значением.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...