Jana Keller
Jana Keller

Reputation: 107

R apply values to column that are closest to list in a loop

I want to create a new column where I assign the value closest to the values of a list, based on another column. This is my data:

df <- data.frame(AV=c("A", "A", "A", "A", "A", "B", "B", "B", "B"), 
                 var=c( 0.1, 0.2, 1.5, 1.8, 8, 1, 1.4, 13, 3))

x <- c(0.5, 1, 2, 5, 10, 20, 40, 80)


for (i in df$var){
  res <- x[which.min(abs(x - i))]
  print(res)}

[1] 0.5
[1] 0.5
[1] 1
[1] 1
[1] 10
[1] 1
[1] 1
[1] 10
[1] 2

I want res to be a new column in my dataframe, however, and struggle with implementing it.

  1. This approach doesn't work, because it doesn't iterate through each row I guess?
f = function(x){x[which.min(abs(x - i))]}

for (i in df$var){
    df$res <- apply(df, 1, f)
}

  1. Including the column in the loop didn't work either:
f = function(x){x[which.min(abs(x - i))]}

for (i in df$var_floor){
  for (j in df$var_floor){
    df$res <- apply(df, 1, f)
}

#Leads to: Error in x - i : non-numeric argument to binary operator 
  1. I tried to do it with apply:
f = function(x){x[which.min(abs(x - i))]}

for (i in df$var){
    res <- apply(df, 1, f)
}


#Leads to: Error in x - i : non-numeric argument to binary operator 

Apply without the for loop didn't work either.

How can I assign the closest value for each row?

Upvotes: 1

Views: 60

Answers (2)

akrun
akrun

Reputation: 887981

One option is findInterval from base R

transform(df, res = x[findInterval(var, x)+1])

Upvotes: 1

bouncyball
bouncyball

Reputation: 10781

We can use sapply:

df$res <- sapply(df$var, FUN = function(v) x[which.min(abs(x - v))])

#   AV var  res
# 1  A 0.1  0.5
# 2  A 0.2  0.5
# 3  A 1.5  1.0
# 4  A 1.8  2.0
# 5  A 8.0 10.0
# 6  B 1.0  1.0
# ...

Upvotes: 3

Related Questions