R有条件地通过查找替换更多列
R conditional replace more columns by lookup
假设我们在数据框 df1 中确实有很多数据列(名称为 mycols 以及一些在这种情况下不应处理的未命名的列) 和一列 subj,它也是另一个数据帧 df2 的索引,列为 repl 和 subj (在第二个数据框中 subj 是唯一的)和许多其他不重要的列(它们在这方面的唯一作用是,我们不能假设只有 2 列)。
我想以这样的方式替换列的子集(df1[mycols]),如果有 NA ( df1[mycols][is.na(df1[mycols])] ) <- 替换为列 df2$repl 其中 df2 中的行有 df2$subj = df1$subj.
编辑:示例数据(我不知道将其写入数据帧分配的命令):
mycols = c("a","b")
df1:
subj a b c
1 NA NA 1
1 2 3 5
2 0 NA 2
3 8 8 8
df2:
subj repl notinterested
1 5 1000
2 6 0
3 40 10
result:
df1-transformed-to:
subj a b c
1 5 5 1 #the 2 fives appeared by lookup
1 2 3 5
2 0 6 2 #the 6 appeared
3 8 8 8
我想出了以下代码:
df1[,mycols][is.na(df1[,mycols])] <- df2[match( df1$subj, df2$subj),"repl"]
但问题是(我认为)右侧与左侧的大小不同 - 我认为它可能适用于“mycols”中的一列,但我想对所有 mycols 执行相同的操作(如果 NA,请查看 table df2 和替换 - 替换值在行的范围内是相同的)。
(我还需要每次都明确地按名称 mycols 枚举列,因为可能还有其他列)
作为关于编程风格的小问题 - 在 R 中,什么是编写此操作的良好且快速的方法?如果它是一种过程语言,我们可以转换
df1[,mycols][is.na(df1[,mycols])]
采用我认为更好、更易读的方法:
function(x){ *x[is.na(*x)] }
function(& df1[,mycols])
可以肯定的是,没有任何东西会被不必要地从一个地方复制到另一个地方。
以下是使用 ifelse()
的可能解决方案:
mycols <- c('a','b');
df1 <- data.frame(subj=c(1,1,2,3), a=c(NA,2,0,8), b=c(NA,3,NA,8), c=c(1,5,2,8) );
df2 <- data.frame(subj=c(1,2,3), repl=c(5,6,40), notinterested=c(1000,0,10) );
df1[mycols] <- ifelse(is.na(df1[mycols]),matrix(df2[match(df1$subj,df2$subj),'repl'],nrow(df1),length(mycols)),as.matrix(df1[mycols]));
df1;
## subj a b c
## 1 1 5 5 1
## 2 1 2 3 5
## 3 2 0 6 2
## 4 3 8 8 8
使用您的代码,我们需要 replicate
'repl' 列使两个子集数据集相等,然后像您一样分配值
val <- df2$repl[match(df1$subj, df2$subj)][row(df1[mycols])][is.na(df1[mycols])]
df1[mycols][is.na(df1[mycols])] <- val
df1
# subj a b c
#1 1 5 5 1
#2 1 2 3 5
#3 2 0 6 2
#4 3 8 8 8
另一个选项使用 data.table
library(data.table)#v1.9.5+
DT <- setDT(df1, key='subj')[df2[c('subj', 'repl')]]
for(j in mycols){
i1 <- which(is.na(DT[[j]]))
set(DT, i=i1, j=j, value= DT[['repl']][i1])
}
DT[,repl:= NULL]
# subj a b c
#1: 1 5 5 1
#2: 1 2 3 5
#3: 2 0 6 2
#4: 3 8 8 8
或 dplyr
library(dplyr)
left_join(df1, df2, by='subj') %>%
mutate_each_(funs(ifelse(is.na(.),repl,.)), mycols) %>%
select(a:c)
# a b c
#1 5 5 1
#2 2 3 5
#3 0 6 2
#4 8 8 8
数据
df1 <- structure(list(subj = c(1L, 1L, 2L, 3L), a = c(NA, 2L, 0L, 8L
), b = c(NA, 3L, NA, 8L), c = c(1L, 5L, 2L, 8L)), .Names = c("subj",
"a", "b", "c"), class = "data.frame", row.names = c(NA, -4L))
df2 <- structure(list(subj = 1:3, repl = c(5L, 6L, 40L),
notinterested = c(1000L,
0L, 10L)), .Names = c("subj", "repl", "notinterested"),
class = "data.frame", row.names = c(NA, -3L))
使用基数 R 执行此操作的一种方法:
mycols = c("a","b")
df1 <- read.table(text="subj a b c
1 NA NA 1
1 2 3 5
2 0 NA 2
3 8 8 8", header = TRUE)
df2 <- read.table(text="subj repl notinterested
1 5 1000
2 6 0
3 40 10", header = TRUE)
df1[mycols] <- lapply(df1[mycols], function(x) {
x[is.na(x)] <- df2$repl[match(df1$subj[is.na(x)], df2$subj)]; x})
假设我们在数据框 df1 中确实有很多数据列(名称为 mycols 以及一些在这种情况下不应处理的未命名的列) 和一列 subj,它也是另一个数据帧 df2 的索引,列为 repl 和 subj (在第二个数据框中 subj 是唯一的)和许多其他不重要的列(它们在这方面的唯一作用是,我们不能假设只有 2 列)。
我想以这样的方式替换列的子集(df1[mycols]),如果有 NA ( df1[mycols][is.na(df1[mycols])] ) <- 替换为列 df2$repl 其中 df2 中的行有 df2$subj = df1$subj.
编辑:示例数据(我不知道将其写入数据帧分配的命令):
mycols = c("a","b")
df1:
subj a b c
1 NA NA 1
1 2 3 5
2 0 NA 2
3 8 8 8
df2:
subj repl notinterested
1 5 1000
2 6 0
3 40 10
result:
df1-transformed-to:
subj a b c
1 5 5 1 #the 2 fives appeared by lookup
1 2 3 5
2 0 6 2 #the 6 appeared
3 8 8 8
我想出了以下代码:
df1[,mycols][is.na(df1[,mycols])] <- df2[match( df1$subj, df2$subj),"repl"]
但问题是(我认为)右侧与左侧的大小不同 - 我认为它可能适用于“mycols”中的一列,但我想对所有 mycols 执行相同的操作(如果 NA,请查看 table df2 和替换 - 替换值在行的范围内是相同的)。
(我还需要每次都明确地按名称 mycols 枚举列,因为可能还有其他列)
作为关于编程风格的小问题 - 在 R 中,什么是编写此操作的良好且快速的方法?如果它是一种过程语言,我们可以转换
df1[,mycols][is.na(df1[,mycols])]
采用我认为更好、更易读的方法:
function(x){ *x[is.na(*x)] }
function(& df1[,mycols])
可以肯定的是,没有任何东西会被不必要地从一个地方复制到另一个地方。
以下是使用 ifelse()
的可能解决方案:
mycols <- c('a','b');
df1 <- data.frame(subj=c(1,1,2,3), a=c(NA,2,0,8), b=c(NA,3,NA,8), c=c(1,5,2,8) );
df2 <- data.frame(subj=c(1,2,3), repl=c(5,6,40), notinterested=c(1000,0,10) );
df1[mycols] <- ifelse(is.na(df1[mycols]),matrix(df2[match(df1$subj,df2$subj),'repl'],nrow(df1),length(mycols)),as.matrix(df1[mycols]));
df1;
## subj a b c
## 1 1 5 5 1
## 2 1 2 3 5
## 3 2 0 6 2
## 4 3 8 8 8
使用您的代码,我们需要 replicate
'repl' 列使两个子集数据集相等,然后像您一样分配值
val <- df2$repl[match(df1$subj, df2$subj)][row(df1[mycols])][is.na(df1[mycols])]
df1[mycols][is.na(df1[mycols])] <- val
df1
# subj a b c
#1 1 5 5 1
#2 1 2 3 5
#3 2 0 6 2
#4 3 8 8 8
另一个选项使用 data.table
library(data.table)#v1.9.5+
DT <- setDT(df1, key='subj')[df2[c('subj', 'repl')]]
for(j in mycols){
i1 <- which(is.na(DT[[j]]))
set(DT, i=i1, j=j, value= DT[['repl']][i1])
}
DT[,repl:= NULL]
# subj a b c
#1: 1 5 5 1
#2: 1 2 3 5
#3: 2 0 6 2
#4: 3 8 8 8
或 dplyr
library(dplyr)
left_join(df1, df2, by='subj') %>%
mutate_each_(funs(ifelse(is.na(.),repl,.)), mycols) %>%
select(a:c)
# a b c
#1 5 5 1
#2 2 3 5
#3 0 6 2
#4 8 8 8
数据
df1 <- structure(list(subj = c(1L, 1L, 2L, 3L), a = c(NA, 2L, 0L, 8L
), b = c(NA, 3L, NA, 8L), c = c(1L, 5L, 2L, 8L)), .Names = c("subj",
"a", "b", "c"), class = "data.frame", row.names = c(NA, -4L))
df2 <- structure(list(subj = 1:3, repl = c(5L, 6L, 40L),
notinterested = c(1000L,
0L, 10L)), .Names = c("subj", "repl", "notinterested"),
class = "data.frame", row.names = c(NA, -3L))
使用基数 R 执行此操作的一种方法:
mycols = c("a","b")
df1 <- read.table(text="subj a b c
1 NA NA 1
1 2 3 5
2 0 NA 2
3 8 8 8", header = TRUE)
df2 <- read.table(text="subj repl notinterested
1 5 1000
2 6 0
3 40 10", header = TRUE)
df1[mycols] <- lapply(df1[mycols], function(x) {
x[is.na(x)] <- df2$repl[match(df1$subj[is.na(x)], df2$subj)]; x})