如何创建一个虚拟变量,说明R中30个相似变量中是否有两个值匹配

vsikbqxv  于 12个月前  发布在  其他
关注(0)|答案(4)|浏览(113)

我不知道该怎么问这个问题。我有一个数据集,看起来像这样。
| ID| B1L1Kod| B2L3Kod| B1L2Kod| B30L1Kod| B1L1par| B2L3par| B1L2par| B30L1par|
| --|--|--|--|--|--|--|--|--|
| 1 | 5 | 6 | 7 | 8 | 9 | 94 | 29 | 69 |
| 1 | 5 | 6 | 7 |NA| 9 | 94 | 29 | 69 |
| 1 | 5 | 6 | 7 | 8 | 9 | 94 | 29 | 69 |
| 1 | 5 | 6 | 7 | 8 |NA| 94 | 29 | 69 |
| 2 | 6 | 7 | 8 | 9 | 9 | 39 | 59 | 39 |
| 2 | 6 | 7 | 8 | 9 | 9 | 39 | 59 | 39 |
我想在R中写一个命令,如果B1 L1 Kod匹配一个特定值,B1 L1 par匹配另一个特定值,则返回一个值为1的新虚拟变量。
我试过以下代码

mutate(´newdummy = case_when(B1L1Kod == '5' & B1L1par == '69' ~ '1', TRUE ~ '0'))

但是,我不想为变量名的所有可能组合重写代码。相反,我希望命令匹配,这样如果前四个数字(B1 L1,B2 L3等)对于每一对来说都是相同的,并且如果特定的值匹配,那么newdummy将返回值1。在同一个数据集中,我还有其他以B1 L1开头的变量,所以命令只需要关注XXXXKod和XXXXpar的组合。
有什么建议?
我完全迷路了,所以我没有尝试任何东西,除了重复上面的命令和改变数字。
/

cbjzeqam

cbjzeqam1#

我们可以写一个小的辅助函数来使比较更容易

find_pair <- function(a, b) {
  function(x) {
    x == a & pick(gsub("Kod$", "par", cur_column()))[[1]]==b
  }
}

这将只在across()上下文中工作,但我们获得当前值,然后使用gsub获得“配对”变量的名称。然后,我们可以将它们与所需的值进行比较。我们会用它,

dd %>% 
  mutate(across(ends_with("Kod"), find_pair("5","69"), .names="{.col}_dummy"))

测试与

dd <- read.table(text="ID   B1L1Kod B2L3Kod B1L2Kod B30L1Kod    B1L1par B2L3par B1L2par B30L1par
                 1  5   6   7   8   9   94  29  69
                 1  5   6   7   NA  9   94  29  69
                 1  5   6   7   8   9   94  29  69
                 1  5   6   7   8   NA  94  29  69
                 2  6   7   8   9   9   39  59  39
                 2  6   7   8   9   9   39  59  39", header=T)
pbwdgjma

pbwdgjma2#

试试这个:

require(stringr)
commoncols<-intersect(str_replace(grep("Kod$", names(df), value = TRUE), "Kod$", ""), 
                      str_replace(grep("par$", names(df), value = TRUE), "par$", ""))
kodcols<-paste0(commoncols, "Kod")
parcols<-paste0(commoncols, "par")
df$dummy<-Reduce("|", Map(\(x,y) df[[x]]=="69" & df[[y]]=="5", kodcols, parcols))

数据

df<-structure(list(ID = c(1L, 1L, 1L, 1L, 2L, 2L), B1L1Kod = c(5L, 
5L, 5L, 5L, 6L, 6L), B2L3Kod = c(6L, 6L, 6L, 6L, 7L, 7L), B1L2Kod = c(7L, 
7L, 7L, 7L, 8L, 8L), B30L1Kod = c(8L, NA, 8L, 8L, 9L, 9L), B1L1par = c(9L, 
9L, 9L, NA, 9L, 9L), B2L3par = c(94L, 94L, 94L, 94L, 39L, 39L
), B1L2par = c(29L, 29L, 29L, 29L, 59L, 59L), B30L1par = c(69L, 
69L, 69L, 69L, 39L, 39L)), class = "data.frame", row.names = c(NA, 
-6L))
pprl5pva

pprl5pva3#

在基R中的一种方法是在你想要的列前缀之间使用sapply

prefixes <- unique(gsub("Kod$|Kap$|par$|mon$", "", names(data)))
prefixes <- prefixes[!grepl("ID", prefixes)]

data[paste0(prefixes, "_indicator")] <- sapply(prefixes, \(x){
  xx <- data[,grep(x, names(data))]
  ifelse(xx[,1] %in% "5" & xx[,2] %in% "69", 1, 0)
})

输出量:

ID B1L1Kod B2L3Kod B1L2Kod B30L1Kod B1L1par B2L3par B1L2par B30L1par B1L1_indicator B2L3_indicator B1L2_indicator B30L1_indicator
1  1       5       6       7        8       9      94      29       69              0              0              0               0
2  1       5       6       7       NA       9      94      29       69              0              0              0               0
3  1       5       6       7        8       9      94      29       69              0              0              0               0
4  1       5       6       7        8      NA      94      29       69              0              0              0               0
5  2       6       7       8        9       9      39      59       39              0              0              0               0
6  2       6       7       8        9       9      39      59       39              0              0              0               0
>

注意:在这里使用%in%而不是==将假设如果任何一列中的值具有NA,则它 * 不是 * 所需的值,因此将返回0。如果您想在任何一列中有NA时返回NA,请将%in%替换为==

gt0wga4j

gt0wga4j4#

这是一个丑陋的hack。……但它很有效……如果不漂亮的话也要快。
所以我用excel来生成其他语言的代码。我只是把文字表达式连接起来。
假设输入变量名和目标值在这样的列中:

然后我可以设置文本代码,使案件与“胶水”,在这种情况下的“&”符号。我手动删除列表末尾元素的字符。
下面是我将插入到case表达式内部的输出列。

下面是Excel代码视图:

下面是第一个代码块的asd:
="(“& D5 &”==“& E5 &”)&“
如果我有上界和下界,或者排除的情况,那么类似地将它们连接起来会非常简单。

相关问题