Find rows with a given difference between values in a column

data.table, dataframe, r

Solution

Here's a `data.table` based solution. I'll be interested to learn what (if any) improvements can be made to it.

# Your code
library(data.table)
source <- 
data.table(data.frame(key = c("A","B","C","D","A","B","A","B","B","B", "C"),
                      value = c(1,1,1,1,4,4,23,23,26,26,30)))

That strange `data.table(data.frame(...` is because `data.table()` has an argument called `key`, too. That's one way to create a `data.table` with a column called `"key"`. Capitalising to avoid the argument name conflict illustrates the more standard syntax :

source <- data.table(Key = c("A","B","C","D","A","B","A","B","B","B","C"),
                     Value = c(1,1,1,1,4,4,23,23,26,26,30))

Next to avoid needing `as.integer()` later, we'll change the type of the `Value` column from `numeric` to `integer` now. Remember than `1` is `numeric` in R, it is `1L` that is `integer`. It is usually better for efficiency to store `integer` data as `integer`, than `integer` as `numeric`. The next line is easier than typing lots of `L`s above.

source[,Value:=as.integer(Value)]   # change type from `numeric` to `integer`

Now proceed

distance <- 22L
setkey(source, Key, Value)

# Heart of the solution (following a few explanatory comments):
#  "J()"   : shorthand for 'data.table()'
#  ".N"    : returns the number of rows that matched a line (see ?data.table)
#  "[[3]]" : as with simple data.frames, extracts the vector in column 3

source[,count:=source[J(Key,Value+distance),.N][[3]]]
source
      key value count
 [1,]   A     1     1
 [2,]   A     4     0
 [3,]   A    23     0
 [4,]   B     1     1
 [5,]   B     4     2
 [6,]   B    23     0
 [7,]   B    26     0
 [8,]   B    26     0
 [9,]   C     1     0
[10,]   C    30     0
[11,]   D     1     0

Note that `:=` changed `source` by reference directly, so that's it. But `setkey()` also changed the order of the original data. If retaining the original order is required, then:

source <- data.table(Key = c("A","B","C","D","A","B","A","B","B","B","C"),
                     Value = c(1,1,1,1,4,4,23,23,26,26,30))
source[,Value:=as.integer(Value)]   
source[,count:=setkey(copy(source))[source[,list(Key,Value+distance)],.N][[3]]]

      Key Value count
 [1,]   A     1     1
 [2,]   B     1     1
 [3,]   C     1     0
 [4,]   D     1     0
 [5,]   A     4     0
 [6,]   B     4     2
 [7,]   A    23     0
 [8,]   B    23     0
 [9,]   B    26     0
[10,]   B    26     0
[11,]   C    30     0

Problem

For a data.table (or data.frame) in R, I wish to find all rows which contain a value in column 'value' which are a given distance 'distance' from another that value in row with the same key. So, given the following: ``` distance <- 22 key value A 1 B 1 C 1 D 1 A 4 B 4 A 23 B 23 B 26 B 26 C 30 ``` I would like to annotated the original table with a count of how many rows exist with the same key, and a value that is +22 from it: ``` key value count A 1 1 B 1 1 C 1 0 D 1 0 A 4 0 B 4 2 A 23 0 B 23 0 B 26 0 B 26 0 C 30 0 ``` I don't really know where to begin with this self-referential approach to manipulating data in R. My initial attempts involved creating a second table and trying to match against that, but that seemed a strange and poor approach. Note: I'm using the `data.table` package but I'm happy to work from data.frame in this case if that makes things easier. Reproducible: ``` require(data.table) source <- data.table(data.frame(key=c("A","B","C","D","A","B","A","B","B","B", "C"),value=c(1,1,1,1,4,4,23,23,26,26,30))) result <- data.table(data.frame(key=c("A","B","C","D","A","B","A","B","B","B","C"),value=c(1,1,1,1,4,4,23,23,26,26,30),count=c(1,1,0,0,0,2,0,0,0,0,0))) ```

Original source