R中的SAS Array等价物

时间:2015-10-15 10:07:47

标签: arrays r

我有一个包含以下列的数据集:

    ID  Measure1    Measure2    XO  X1  x2  x3  x4  x5
    1   30  2   item1   item1   item23  NA      item6   item9
    2   23  2   item1   item323 item1   item4   item5   NA      
    3   2   2   item1   item78  item3   NA      item1   item5

我想用R:

中的这段SAS代码创建一个标志变量
 data dt2;
 set dt1;
 array x {5} x1 - x5;
 do i=1 to 5;
 if x0=x{i} then do; 
 flag=i;
 leave;
 end;
 end;
 drop i;
 run;

目标是能够浏览x1-x5的值并查看xo与其中任何一个相等的位置并返回位置,例如,如果在x1处找到item1,则返回到值1,如果在位置x3返回3.

最终产品看起来像这样:

    ID  Measure1    Measure2    XO  X1  x2  x3  x4  x5  Flag
    1   30  2   item1   item1   item23  NA          item6   item9   1
    2   23  2   item1   item323 item1   item4       item5   NA      2
    3   2   2   item1   item78  item3   NA          item1   item5   4

请记住,可能存在所有行x1-x5都包含NA的情况,在这种情况下我想返回空白,这可能吗?

我无法在R中找到与动态意义相同的东西(没有使用sqldf编写多个if语句或大小写)因为现在列可能是5但可以在将来更改为最多20个

有什么想法吗?

2 个答案:

答案 0 :(得分:4)

我们可以使用max.col

df1$Flag <- max.col(df1$XO[row(df1[-1])]==df1[-1], 'first')
df1
#    XO      X1     x2     x3    x4    x5 Flag
#1 item1   item1 item23  item5 item6 item9    1
#2 item1 item323  item1  item4 item5 itm87    2
#3 item1  item78  item3 item98 item1 item5    4

更新

根据更新的数据集,我们可以用FALSE替换逻辑矩阵中的NA元素,然后使用max.col。如果一行中没有TRUE值,我们可以通过获取NA将其设为rowSums,检查它是否为0,将值更改为0到NA(NA^..)和乘以max.col(.

df3 <- df2[5:ncol(df2)]
i1 <- df2$XO[row(df3)]==df3
i2 <- replace(i1, is.na(i1), FALSE)
df2$Flag <- max.col(i2, 'first') * NA^(rowSums(i2)==0)
df2
#  ID Measure1 Measure2    XO      X1     x2    x3    x4    x5 Flag
#1  1       30        2 item1   item1 item23  <NA> item6 item9    1
#2  2       23        2 item1 item323  item1 item4 item5  <NA>    2
#3  3        2        2 item1  item78  item3  <NA> item1 item5    4

答案 1 :(得分:1)

1)base R as.matrix(DF[5:9]) == XO生成一个与DF[5:9]具有相同尺寸的逻辑矩阵。将wm应用于每一行。 wmwhich.max相同,只是在没有TRUE值的情况下返回NA,即如果一行中只有NA和FALSE值。如果没有这种情况,那么我们可以使用which.max代替wm将解决方案减少到一行。如果一行中有多个TRUE值,它将使用第一个。

wm <- function(x) if (isTRUE(any(x))) which.max(x) else NA
transform(DF, Flag = apply(as.matrix(DF[-(1:4)]) == XO, 1, wm))

,并提供:

  ID Measure1 Measure2    XO      x1     x2    x3    x4    x5 Flag
1  1       30        2 item1   item1 item23  <NA> item6 item9    1
2  2       23        2 item1 item323  item1 item4 item5  <NA>    2
3  3        2        2 item1  item78  item3  <NA> item1 item5    4

2)dplyr / tidyr 这里的主要复杂性是数据未规范化,而是x1,...,xn列以宽格式写入。为了解决这个问题,我们可以使用tidyr的gather将数据框转换为长格式,检查项目是否等于XO并加入到原始数据框:

library(dplyr)
library(tidyr)
DF %>% 
   left_join(DF %>% gather(Flag, item, -(1:4)) %>% filter(item == XO)) %>%
   select(-item) %>%
   mutate(Flag = match(Flag, names(DF)[-(1:4)]))

,并提供:

  ID Measure1 Measure2    XO      X1     x2    x3    x4    x5 Flag
1  1       30        2 item1   item1 item23  <NA> item6 item9    1
2  2       23        2 item1 item323  item1 item4 item5  <NA>    2
3  3        2        2 item1  item78  item3  <NA> item1 item5    4

3)另一种基础解决方案此基础解决方案的灵感来自dplyr / tidyr解决方案。它使用reshape将原始数据帧转换为长格式,它选取相等的行,然后将Flag变量合并到原始数据帧:

r <- reshape(DF, list(names(DF)[-(1:4)]), "X", "Flag", direction = "long")
s <- subset(r, X == XO)[c("ID", "Flag")]
merge(DF, s, all.x = TRUE)

,并提供:

  ID Measure1 Measure2    XO      X1     x2    x3    x4    x5 Flag
1  1       30        2 item1   item1 item23  <NA> item6 item9    1
2  2       23        2 item1 item323  item1 item4 item5  <NA>    2
3  3        2        2 item1  item78  item3  <NA> item1 item5    4

注意:为了使这个可重现,我们提供了在下面创建输入的代码。下次请自己提供。

Lines <- "  ID  Measure1    Measure2    XO  x1  x2  x3  x4  x5
    1   30  2   item1   item1   item23  NA      item6   item9
    2   23  2   item1   item323 item1   item4   item5   NA      
    3   2   2   item1   item78  item3   NA      item1   item5"

DF <- read.table(text = Lines, header = TRUE, as.is = TRUE)