2

I have a data set with multiple columns containing quantitative data that I want to transform into binary. To do, I would like to use thresholds that are different for each column.

Example

Input:

  antigen1 antigen2 antigen3 antigen4
1      215      421        2       12
2     1524       33      112      443
3      944      836      343       32
4       53      321      563        4

Code to generate the data set:

input <- data.frame(
  antigen1 = c(215,1524,944,53),
  antigen2 = c(421, 33, 836,321),
  antigen3 = c(2,112,343,563),
  antigen4 = c(12,443,32,4))

Thresholds for each column, for antigen1 to antigen4 respectively: 100, 50, 400, 100

Output:

  antigen1 antigen2 antigen3 antigen4
1        1        1        0        0
2        1        0        0        1
3        1        1        0        0
4        0        1        1        0

This is what I've tried, using R:

# Define lists
cut_offs <- c(100,50,400,100)
antigens <- names(input[1:ncol(input)])

# Loop through both lists
for (anti in antigens) {
  for (co in cut_offs) {
    input[[anti]][input[[anti]]]<cut_offs[co] <- 0 
    input[[anti]][input[[anti]]]>=cut_offs[co] <- 1
  }
}

How can I make both "anti" and "co" increase simultaneously by one after each loop?

2 Answers2

2

We can do this in a vectorized manner without any loops

+(input >= cut_offs[col(input)])
#      antigen1 antigen2 antigen3 antigen4
#[1,]        1        1        0        0
#[2,]        1        0        0        1
#[3,]        1        1        0        0
#[4,]        0        1        1        0
akrun
  • 874,273
  • 37
  • 540
  • 662
0

We could use mapply

+(mapply(`>=`, input, cut_offs))

#     antigen1 antigen2 antigen3 antigen4
#[1,]        1        1        0        0
#[2,]        1        0        0        1
#[3,]        1        1        0        0
#[4,]        0        1        1        0

We can wrap it in data.frame if you need data frame as final output

data.frame(+(mapply(`>=`, input, cut_offs)))

Or with sapply

sapply(seq_along(cut_offs), function(x) +(input[, x] > cut_offs[x]))

As far as your for loop is concerned you need only one loop since length(cut_offs) would be equal to number of columns in input, so we can loop over them using same index.

temp <- replace(input, TRUE, 0) #Initialise with all values as 0

for (x in seq_along(cut_offs)) {
    temp[input[, x] >= cut_offs[x], x] <- 1 
}

temp
#  antigen1 antigen2 antigen3 antigen4
#1        1        1        0        0
#2        1        0        0        1
#3        1        1        0        0
#4        0        1        1        0
Ronak Shah
  • 377,200
  • 20
  • 156
  • 213