基于第二数据帧中的值过滤数据帧

Dal*_*i71 9 r subset dataframe

我有2个数据框:

at1 = data.frame(ID = c("A", "B", "C", "D", "E"), Sample1 = rnorm(5, 50000, 2500),
      Sample2 = rnorm(5, 50000, 2500), Sample3 = rnorm(5, 50000, 2500),
      row.names = "ID")

  Sample1  Sample2  Sample3
A 52626.55 51924.51 50919.90
B 51430.51 49100.38 51005.92
C 50038.27 52254.73 50014.78
D 48644.46 53926.53 51590.05
E 46462.01 45097.48 50963.39

bt1 = data.frame(ID = c("A", "B", "C", "D", "E"), Sample1 = c(0,1,1,1,1),
      Sample2 = c(0,0,0,1,0), Sample3 = c(1,0,1,1,0), 
      row.names = "ID")

   Sample1 Sample2 Sample3
A       0       0       1
B       1       0       0
C       1       0       1
D       1       1       1
E       1       0       0
Run Code Online (Sandbox Code Playgroud)

我想基于bt1(0或1)中相应单元格中的值过滤at1中的每个单元格,并将结果存储在新数据框架ct1中.例如,如果bt1 [1,"Sample1"] = 1,则ct1 [1,"Sample1"] = at1 [1,"Sample1"].如果bt1 [1,"Sample1"] = 0,则ct1 [1,"Sample1"] = 0.我的原始数据帧有超过100列和超过30,000行.

我想知道是否有比写if循环更简单的方法(例如使用"apply"?).

mne*_*nel 7

这是一个data.table解决方案,也是第二个简单的解决方案

请注意,我已经提出ID了一个特定的专栏,而data.frame不是row.names 出于意识形态和实际原因

  • a data.table没有rownames
  • 我认为将它们视为数据的一部分更容易

library(data.table)
library(reshape2)

bt1 <- data.frame(ID = c("A", "B", "C", "D", "E"), Sample1 = c(0,1,1,1,1),
   Sample2 = c(0,0,0,1,0), Sample3 = c(1,0,1,1,0))

at1 <- data.frame(ID = c("A", "B", "C", "D", "E"), Sample1 = rnorm(5, 50000, 2500),
  Sample2 = rnorm(5, 50000, 2500), Sample3 = rnorm(5, 50000, 2500))

# place in long form
at_long <- data.table(melt(at1, id.var = 1))
bt_long <- data.table(melt(bt1, value.name = 'bt_value', id.var = 1))
# set keys for easy merging with data.tabl
setkeyv(at_long, c('ID','variable'))
setkeyv(bt_long, c('ID','variable'))
# merge
combined <- at_long[bt_long]
# set those where 'bt_value == 0' as 0
set(combined, which(combined[['bt_value']]==0), 'value',0)
# or (using the fact that the `bt` data is only 0 or 1
combined[value := value * bt_value]
# then reshape to wide format
dcast(combined, ID~variable, value.var = 'value')
##   ID  Sample1  Sample2  Sample3
## 1  A     0.00     0.00 50115.24
## 2  B 50173.16     0.00     0.00
## 3  C 48216.31     0.00 51952.30
## 4  D 52387.53 50889.95 44043.66
## 5  E 50982.56     0.00     0.00
Run Code Online (Sandbox Code Playgroud)

第二种,简单化的方法

如果您知道行bt1at1(和您的数据集)中的行顺序相同,则可以简单地将data.frames的相应组件相乘(以*元素方式工作)

sample_cols <- paste0('Sample',1:3)
at1[,sample_cols] * bt1[,sample_cols]

##    Sample1  Sample2  Sample3
## 1     0.00     0.00 50115.24
## 2 50173.16     0.00     0.00
## 3 48216.31     0.00 51952.30
## 4 52387.53 50889.95 44043.66
## 5 50982.56     0.00     0.00
Run Code Online (Sandbox Code Playgroud)

您可以cbind在到IDat1bt1,或者保持IDrow.names,那么row.names将持续.


mat*_*fee 5

您可以使用矢量化(以及其他内容).

例如:

ct1 <- at1                           # set ct1 equal to at1
ct1$Sample1[bt1$Sample1 == 0] <- 0   # if bt1$Sample1 = 0, set the value to 0
Run Code Online (Sandbox Code Playgroud)

对于第二行:bt1$Sample1 == 0是一个逻辑向量,TRUEif bt1$Sample1为0,然后我们将其用作索引ct1,以便将这些值设置为0.由于ct1初始化为at1,所有其他行(where bt1$Sample1 == 1)都设置为值在at1.

另一种方法是使用ifelse,这是if语句的矢量化形式:

ct1$Sample1 <- ifelse(bt1$Sample1 == 0, 0, at1$Sample1)
Run Code Online (Sandbox Code Playgroud)

它表示"对于每一行bt1$Sample1,如果bt1$Sample1[row] == 0替换为0,则以其他方式替换at1$Sample1[row].

您可以为您感兴趣的每个列重复此操作.

你可以遍历列,或者你可以使用类似vapply的说:

for each column `col` in bt1:
    ct1$col <- ifelse(bt1$col == 0, 0, at1$col)
Run Code Online (Sandbox Code Playgroud)

这可以通过以下方式实现:

ct1 <- vapply(colnames(bt1), function (col) {
           ifelse(bt1[[col]] == 0, 0, at1[[col]])
        }, FUN.VALUE=at1$Sample1)
Run Code Online (Sandbox Code Playgroud)

?vapply,但简而言之:

  • colnames(bt1)手段"中的每一列bt",
  • function (col) { ifelse(bt1[[col]] == 0, 0, at1[[col]]) }是本声明的伪代码以上:值eqqual设置为0,如果BT1是0,在设置为值at1否则,
  • FUN.VALUE=at1$Sample1是因为vapply需要一个函数输出的例子(在我们的例子中,是一个数据框的列).


shh*_*its 5

使用厚颜无耻的方法 sqldf

library(sqldf)
variables <- "bt1.Sample1*at1.Sample1 Sample1,
    bt1.Sample2*at1.Sample2 Sample2,
    bt1.Sample3*at1.Sample3 Sample3"

fn$sqldf("SELECT $variables from at1,bt1 WHERE at1.ROWID=bt1.ROWID")


#   Sample1  Sample2  Sample3
#1     0.00     0.00 55778.34
#2 48819.24     0.00     0.00
#3 51896.14     0.00 52522.69
#4 47946.93 48604.23 47755.30
#5 49423.68     0.00     0.00
Run Code Online (Sandbox Code Playgroud)