我有一个包含以下列的数据集:
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个
有什么想法吗?
答案 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
应用于每一行。 wm
与which.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)