自定义数据相关的重新编码到 R 中的逻辑
Custom data-dependent recoding to logicals in R
我有两个数据框,data
和 meta
。 data
中的一些(但不是全部)列是逻辑值,但它们以许多不同的方式编码。 meta
中的行描述了 data
中的列,指示它们是否被解释为逻辑,如果是,哪些单值代码为 TRUE,哪些单值代码为 FALSE。
我需要一个过程,将概念逻辑列中的所有 data
值替换为相应 meta
行中代码的适当逻辑值。与相应 meta
行中的值不匹配的概念逻辑列中的任何 data
值都应变为 NA。
meta
的小玩具示例:
name type false true
-----------------------------------------
a.char.var char NA NA
a.logical.var logical NA 7
another.logical.var logical 1 0
another.char.var char NA NA
data
的小玩具示例:
a.char.var a.logical.var another.logical.var another.char.var
----------------------------------------------------------------
aa 7 0 ba
ab NA 1 bb
ac 7 NA bc
ad 4 3 bd
小玩具示例输出:
a.char.var a.logical.var another.logical.var another.char.var
----------------------------------------------------------------
aa TRUE TRUE ba
ab FALSE FALSE bb
ac TRUE NA bc
ad NA NA bd
我这辈子都找不到在惯用的 R 中处理所有极端情况的方法。数据集很大,因此如果可能的话,惯用的解决方案将是理想的。我继承了这个绝对疯狂的数据管理混乱,我将感谢任何能帮助修复它的人。我绝不是 R 大师,但这似乎是一个看似困难的问题。
我编写了一个函数,它接受 data
的列索引并尝试执行您描述的操作。
该函数首先选择 x
作为我们感兴趣的列。然后我们将 data
中的列名称与 meta
的第一列中的条目进行匹配,这引起了我们的兴趣。
然后我们检查列类型是否为 logical
,如果不是,我们只是 return x
,不需要更改任何内容。如果列类型是 logical
,我们将检查其值是否与 meta
中的 true
或 false
列匹配。
convert_data <- function(colindex, dat, meta = meta){
x <- dat[,colindex] #select our data vector
#match the column name to the first column in meta
find_in_meta <- match(names(dat)[colindex],
meta[,1])
#what type of column is it
type_col <- meta[find_in_meta,2]
if(type_col != 'logical'){
return(x)
}else{
#fix if logical is NA
true_val <- ifelse(is.na(meta[find_in_meta,4]),'NA_val',
meta[find_in_meta,4])
#fix if logical is NA
false_val <- ifelse(is.na(meta[find_in_meta,3]), 'NA_val',
meta[find_in_meta, 3])
#fix if logical is NA
x <- ifelse(is.na(x), 'NA_val', x)
x <- ifelse(x == true_val, TRUE,
ifelse(x == false_val, FALSE, NA))
return(x)
}
}
然后我们可以使用 lapply
和一些数据操作使其成为可接受的形式:
res <- lapply(1:ncol(df1), function(ind)
convert_data(colindex = ind, dat = df1, meta = meta))
setNames(do.call('cbind.data.frame', res), names(df1))
a.char.var a.logical.var another.logical.var another.char.var
1 aa TRUE TRUE ba
2 ab FALSE FALSE bb
3 ac TRUE NA bc
4 ad NA NA bd
数据
meta <- structure(list(name = c("a.char.var", "a.logical.var", "another.logical.var",
"another.char.var"), type = c("char", "logical", "logical", "char"
), false = c(NA, NA, 1L, NA), true = c(NA, 7L, 0L, NA)), .Names = c("name",
"type", "false", "true"), class = "data.frame", row.names = c(NA,
-4L))
df1 <- structure(list(a.char.var = c("aa", "ab", "ac", "ad"), a.logical.var = c(7L,
NA, 7L, 4L), another.logical.var = c(0L, 1L, NA, 3L), another.char.var = c("ba",
"bb", "bc", "bd")), .Names = c("a.char.var", "a.logical.var",
"another.logical.var", "another.char.var"), class = "data.frame", row.names = c(NA,
-4L))
首先我们设置数据
meta <- data.frame(name=c('a.char.var', 'a.logical.var', 'another.logical.var', 'another.char.var'),
type=c('char', 'logical', 'logical', 'char'),
false=c(NA, NA, 1, NA),
true=c(NA, 7, 0, NA), stringsAsFactors = F)
data <- data.frame(a.char.var=c('aa', 'ab', 'ac', 'ad'),
a.logical.var=c(7, NA, 7, 4),
another.logical.var=c(0,1,NA,3),
another.char.var=c('ba', 'bb', 'bc', 'bd'), stringsAsFactors = F)
然后我们只对逻辑列进行子集化。我们将遍历这些,使用 name
列到 select data
中的相关列,并将 data_out
中的值从初始化的 NA
更改为 T
或 F
根据 data
.
中的匹配值
请注意,如果 logical_meta$name
是一个字符,则 data[,logical_meta$name[1]]
等同于 data[,'a.logical.var']
或 data$a.logical.var
。如果它是一个因素(例如,如果我们没有指定 stringsAsFactors=F
),我们需要转换为字符,此时我们不妨给它一个名称 - 下面的 colname
。
让 NA 来应对意味着使用 which
是有利的:c(0, 1,NA,3)==0
returns T,F,NA,F
但是 which
然后忽略 NA
和returns 就是位置 1
。由包含 NA 的逻辑向量子集产生 NA 行或列,使用 which
消除了这一点。
logical_meta <- meta[meta$type=='logical',]
data_out <- data #initialize
for(i in 1:nrow(logical_meta)) {
colname <- as.character(logical_meta$name[i]) #only need as.character if factor
data_out[,colname] <- NA
#false column first
if(is.na(logical_meta$false[i])) {
data_out[is.na(data[,colname]),colname] <- FALSE
} else {
data_out[which(data[,colname]==logical_meta$false[i]),
colname] <- FALSE
}
#true column next
if(is.na(logical_meta$true[i])) {
data_out[is.na(data[,colname]),colname] <- TRUE
} else {
data_out[which(data[,colname]==logical_meta$true[i]),
colname] <- TRUE
}
}
data_out
我有两个数据框,data
和 meta
。 data
中的一些(但不是全部)列是逻辑值,但它们以许多不同的方式编码。 meta
中的行描述了 data
中的列,指示它们是否被解释为逻辑,如果是,哪些单值代码为 TRUE,哪些单值代码为 FALSE。
我需要一个过程,将概念逻辑列中的所有 data
值替换为相应 meta
行中代码的适当逻辑值。与相应 meta
行中的值不匹配的概念逻辑列中的任何 data
值都应变为 NA。
meta
的小玩具示例:
name type false true
-----------------------------------------
a.char.var char NA NA
a.logical.var logical NA 7
another.logical.var logical 1 0
another.char.var char NA NA
data
的小玩具示例:
a.char.var a.logical.var another.logical.var another.char.var
----------------------------------------------------------------
aa 7 0 ba
ab NA 1 bb
ac 7 NA bc
ad 4 3 bd
小玩具示例输出:
a.char.var a.logical.var another.logical.var another.char.var
----------------------------------------------------------------
aa TRUE TRUE ba
ab FALSE FALSE bb
ac TRUE NA bc
ad NA NA bd
我这辈子都找不到在惯用的 R 中处理所有极端情况的方法。数据集很大,因此如果可能的话,惯用的解决方案将是理想的。我继承了这个绝对疯狂的数据管理混乱,我将感谢任何能帮助修复它的人。我绝不是 R 大师,但这似乎是一个看似困难的问题。
我编写了一个函数,它接受 data
的列索引并尝试执行您描述的操作。
该函数首先选择 x
作为我们感兴趣的列。然后我们将 data
中的列名称与 meta
的第一列中的条目进行匹配,这引起了我们的兴趣。
然后我们检查列类型是否为 logical
,如果不是,我们只是 return x
,不需要更改任何内容。如果列类型是 logical
,我们将检查其值是否与 meta
中的 true
或 false
列匹配。
convert_data <- function(colindex, dat, meta = meta){
x <- dat[,colindex] #select our data vector
#match the column name to the first column in meta
find_in_meta <- match(names(dat)[colindex],
meta[,1])
#what type of column is it
type_col <- meta[find_in_meta,2]
if(type_col != 'logical'){
return(x)
}else{
#fix if logical is NA
true_val <- ifelse(is.na(meta[find_in_meta,4]),'NA_val',
meta[find_in_meta,4])
#fix if logical is NA
false_val <- ifelse(is.na(meta[find_in_meta,3]), 'NA_val',
meta[find_in_meta, 3])
#fix if logical is NA
x <- ifelse(is.na(x), 'NA_val', x)
x <- ifelse(x == true_val, TRUE,
ifelse(x == false_val, FALSE, NA))
return(x)
}
}
然后我们可以使用 lapply
和一些数据操作使其成为可接受的形式:
res <- lapply(1:ncol(df1), function(ind)
convert_data(colindex = ind, dat = df1, meta = meta))
setNames(do.call('cbind.data.frame', res), names(df1))
a.char.var a.logical.var another.logical.var another.char.var
1 aa TRUE TRUE ba
2 ab FALSE FALSE bb
3 ac TRUE NA bc
4 ad NA NA bd
数据
meta <- structure(list(name = c("a.char.var", "a.logical.var", "another.logical.var",
"another.char.var"), type = c("char", "logical", "logical", "char"
), false = c(NA, NA, 1L, NA), true = c(NA, 7L, 0L, NA)), .Names = c("name",
"type", "false", "true"), class = "data.frame", row.names = c(NA,
-4L))
df1 <- structure(list(a.char.var = c("aa", "ab", "ac", "ad"), a.logical.var = c(7L,
NA, 7L, 4L), another.logical.var = c(0L, 1L, NA, 3L), another.char.var = c("ba",
"bb", "bc", "bd")), .Names = c("a.char.var", "a.logical.var",
"another.logical.var", "another.char.var"), class = "data.frame", row.names = c(NA,
-4L))
首先我们设置数据
meta <- data.frame(name=c('a.char.var', 'a.logical.var', 'another.logical.var', 'another.char.var'),
type=c('char', 'logical', 'logical', 'char'),
false=c(NA, NA, 1, NA),
true=c(NA, 7, 0, NA), stringsAsFactors = F)
data <- data.frame(a.char.var=c('aa', 'ab', 'ac', 'ad'),
a.logical.var=c(7, NA, 7, 4),
another.logical.var=c(0,1,NA,3),
another.char.var=c('ba', 'bb', 'bc', 'bd'), stringsAsFactors = F)
然后我们只对逻辑列进行子集化。我们将遍历这些,使用 name
列到 select data
中的相关列,并将 data_out
中的值从初始化的 NA
更改为 T
或 F
根据 data
.
请注意,如果 logical_meta$name
是一个字符,则 data[,logical_meta$name[1]]
等同于 data[,'a.logical.var']
或 data$a.logical.var
。如果它是一个因素(例如,如果我们没有指定 stringsAsFactors=F
),我们需要转换为字符,此时我们不妨给它一个名称 - 下面的 colname
。
让 NA 来应对意味着使用 which
是有利的:c(0, 1,NA,3)==0
returns T,F,NA,F
但是 which
然后忽略 NA
和returns 就是位置 1
。由包含 NA 的逻辑向量子集产生 NA 行或列,使用 which
消除了这一点。
logical_meta <- meta[meta$type=='logical',]
data_out <- data #initialize
for(i in 1:nrow(logical_meta)) {
colname <- as.character(logical_meta$name[i]) #only need as.character if factor
data_out[,colname] <- NA
#false column first
if(is.na(logical_meta$false[i])) {
data_out[is.na(data[,colname]),colname] <- FALSE
} else {
data_out[which(data[,colname]==logical_meta$false[i]),
colname] <- FALSE
}
#true column next
if(is.na(logical_meta$true[i])) {
data_out[is.na(data[,colname]),colname] <- TRUE
} else {
data_out[which(data[,colname]==logical_meta$true[i]),
colname] <- TRUE
}
}
data_out