在 tidyr::extract 中使用正则表达式

Using regular expressions in tidyr::extract

我正在处理 3D motion-capture 数据。这意味着我在 body 中有几个关节的关节坐标的 3 列 (X,Y,Z)(例如,描述左膝关节中心位置的三列是:LKX、LKY、LKZ)。

我的最终目标是绘制至少 9 个联合中心,我相信实现这一目标的唯一方法是将我的宽格式数据框转换为长格式数据框。

如您所知,我正在尝试转换多组以 X、Y 或 Z 结尾的关节中心。因此,我尝试在 tidyr:extract 中使用正则表达式,但我就是做不到正确输入代码。

df_wide <- data.frame(
  ID = rep(1:2, each=10),
  JN = rep(1:2, each=5),
  Frame = rep(1:5, 4),
  System = rep(1:2, 10),
  RKX = rep(1:10+rnorm(10,mean=1,sd=0.5),2),
  RKY = rep(1:10+rnorm(10,mean=1,sd=0.5),2),
  RKZ = rep(1:10+rnorm(10,mean=1,sd=0.5), 2),
  LHeX = rep(1:10-rnorm(10,mean=1,sd=0.5),2),
  LHeY = rep(1:10-rnorm(10,mean=1,sd=0.5),2),
  LHeZ = rep(1:10-rnorm(10,mean=1,sd=0.5),2))

head(df_wide, 2)
  ID JN Frame System      RKX      RKY      RKZ        LHeX       LHeY      LHeZ
1  1  1     1      1 1.332827 2.068720 2.295742 -0.02336031 -0.3011227 -1.212326
2  1  1     2      2 3.570076 3.306799 3.136177  2.08828231  1.9226740  2.106496

我希望得到这个结果:

   ID JN Frame System joint         X         Y         Z
1   1  1     1      1    RK  1.440103  2.221676  1.621871
2   1  1     1      1   LHe  3.537940  3.060948  2.856955

这是我最近的(多次)尝试。它有两个问题; 1) extract 只产生 NA; 2) spread returns "Error: Duplicate identifiers for rows" 我怀疑这与提取物的问题有关。

df_3D <- df_wide %>%
 gather(keys, values, -ID, -JN, -Frame, -System)%>% 
  extract(keys, c("X", "Y", "Z", "joint"), "(X$) (Y$) (Z$) ([A-Z].$)")%>% 
  spread(X, values)

我发现了几个关于转换的很好的问题和答案,但其中 none 专门针对正则表达式的使用。

您需要将数据收集成超长格式,然后拆分维度,然后将数据散布回 X、Y 和 Z 列:

library(tidyr)
library(stringr)

df2  <- df_wide %>% 
  # leave the other columns
  gather( jointid, position, -ID, -JN, -Frame, -System ) %>% 
  # insert a seperator to make it easier to split the X/Y/Z from the joint name
  mutate(jointid = str_replace( jointid, "X|Y|Z", ";\0")) %>% 
  # split the joint name and the dimension apart
  tidyr::separate(jointid, c('joint', 'dim'), sep = ";" ) %>% 
  # spread the joint and position apart into 3 columns
  spread(dim, position)

你的做法有点不对。收集后 keys 列的每个元素都具有结构 <Joint><Coord>,因此您需要如下内容:

df_wide %>%
    gather(keys, values, -ID, -JN, -Frame, -System) %>%
    extract(keys, c("Joint", "Coord"), "(.*)(X|Y|Z)$") %>%
    spread(Coord, values)

我在这里使用的正则表达式捕获第一组中的任何内容(因为我不知道所有可能的联合名称),然后 X 或 Y 或 Z 作为第二组中的最后一个字符。还有很多其他正则表达式可以实现同样的目的。

输出:

   ID JN Frame System Joint          X          Y           Z
1   1  1     1      1   LHe  0.1344259 -0.2927277  0.05375166
2   1  1     1      1    RK  1.8083539  2.4053498  2.32899399
3   1  1     2      2   LHe  1.1777492  1.1780538  0.96549849
4   1  1     2      2    RK  3.2254236  2.4100235  2.79816371