Calculating difference with only natural numbers in R

Viewed 67

I want to classify my data based on the difference in 2 years.
I wanted to use the diff function but it does not work with negative numbers.

I get this error

'lag' and 'differences' must be integers >= 1
df$new_var <- fcase(
  df$year1== df$year2, '4',
  diff(df$year1, df$year2) <= 5, '3',  
  diff(df$ipodate1, df$ipodate2) <= 10, '2',
  default = '0'
)

Is there a way I can calculate differences in absolute values

df <- data.frame(
  year1 = c('1997','2008','2004','2010','2005','2007','2008'),
  year2 = c('1997','2018','1988','1929','2023','2012','2009'))

So the end should look sth like this:

year1 year2 new_var
1997 1997 4
2008 20018 2
2004 1988 0

...

4 Answers

Here I will turn df into the numeric type firstly. Then I prefer to use fcase in the data.table method as the following

library(data.table)
df <- data.frame(
  year1 = c('1997','2008','2004','2010','2005','2007','2008'),
  year2 = c('1997','2018','1988','1929','2023','2012','2009')
)

% to numeric type
df2 <- data.frame(apply(df,2, FUN=function(x) as.numeric(x)))

setDT(df2)[,newvar:=fcase(year1 == year2,4,
                          abs(year1 - year2) <= 5, 3,
                          abs(year1 - year2) <= 10, 2,
                          default = 0)]
#   year1 year2 newvar
#1:  1997  1997      4
#2:  2008  2018      2
#3:  2004  1988      0
#4:  2010  1929      0
#5:  2005  2023      0
#6:  2007  2012      3
#7:  2008  2009      3

Here is a dplyr way using case_when and abs:

library(dplyr)
df %>%  
  type.convert(as.is = TRUE) %>% 
  mutate(new_var = case_when(year1 == year2 ~ 4,
                             abs(year1-year2) <=5 ~3,
                             abs(year1-year2) <=10 ~2,
                             TRUE ~ 0))

output:

  year1 year2 new_var
1  1997  1997       4
2  2008  2018       2
3  2004  1988       0
4  2010  1929       0
5  2005  2023       0
6  2007  2012       3
7  2008  2009       3

You may use cut passing breaks and labels.

df <- type.convert(df, as.is = TRUE)
df$new_var <- cut(abs(df$year1 - df$year2),c(-Inf, 0, 5, 10, Inf), c(4, 3, 2, 0))
df

#  year1 year2 new_var
#1  1997  1997       4
#2  2008  2018       2
#3  2004  1988       0
#4  2010  1929       0
#5  2005  2023       0
#6  2007  2012       3
#7  2008  2009       3

We can also use findInterval, which is more efficient

df$new_var <- c(4, 3, 2, 0)[findInterval(abs(Reduce(`-`, type.convert(df, 
    as.is = TRUE))), c(-Inf, 0, 5, 10, Inf), left.open = TRUE)]
df$new_var
[1] 4 2 0 0 0 3 3
Related