如何根据值之间的差异减去R中数据帧中的行?

时间:2018-04-13 20:50:14

标签: r dataframe data-science

我有一个格式如下的数据框

df <- data.frame(name=LETTERS[1:5], location=c(2000,2021,4532,1931,3457),
                 value=c(1,0,1,1,0))

name    location   value
A       2000       1
B       2021       0
C       4532       1
D       1931       1
E       3457       0

数据框中有大约一百万行。如果位置在彼此的1000之内,我如何创建一个具有每个位置之间距离的新数据帧,还会检查两个位置的值是否都是一个?

对于上述数据集,数据框中只有三行,其值为21(绝对值为2000 - 2021),69(绝对值为2000 - 1931)和90(绝对值为2021-1931) )因为这些是唯一小于1000的差异。它也会有一列0(因为A和B值不是1和1),1(因为A和C值是1和1)和0(因为B和C不是1和1)。所以它看起来像:

21   0
69   1
90   0

我尝试过使用循环,但由于行数太多,效率很低。是否有一些内置功能,我应该用它来更快地做到这一点? 提前谢谢。

2 个答案:

答案 0 :(得分:4)

library(sqldf)
sqldf("
select  a.location
        , b.location
        , a.location - b.location as locdiff
        , a.value*b.value as value
from    df a
        inner join df b
          on a.location - b.location between 1 and 1000
")

这给出了

  a.location b.location locdiff value
1       2000       1931      69     1
2       2021       2000      21     0
3       2021       1931      90     0

data.table。这只是@MKR的解决方案,但添加了一列以避免大的连接结果。不确定是否可以在不创建新列的情况下实现此目的。

setDT(df)

df[, loc2 :=  location - 1000]

df[df 
  , .( locdiff   = i.location - x.location
     , locationA = i.location
     , locationB = x.location
     , value     = x.value*i.value)
  , on = .(location >= loc2 
          , location < location)
  , nomatch = 0]

给出

   locdiff locationA locationB value
1:      69      2000      1931     1
2:      90      2021      1931     0
3:      21      2021      2000     0

答案 1 :(得分:2)

我同意@Gregor的评论,他提到sqldf在上面的场景中更好的选择,因为它避免了百万条记录的笛卡尔连接。

但我尝试优化基于data.table的解决方案,首先加入x.location > i.location,然后过滤diff <=1000

df <- data.frame(name=LETTERS[1:5], location=c(2000,2021,4532,1931,3457),
                 value=c(1,0,1,1,0))
library(data.table)
setDT(df)

df[df,.(name, diff = x.location - i.location, value = x.value*i.value), 
         on=.(location > location), nomatch=0][diff<=1000]
#    name diff value
# 1:    B   21     0
# 2:    A   69     1
# 3:    B   90     0