R数据表外连接按功能划分

时间:2016-07-29 20:59:45

标签: r

我有一个包含以下列的数据表:

name, x, y
a, 1, 2
b, 2, 3
c, 3, 1

我希望自己加入此表,将每一行保持在name != name,并在每一侧的xy值上运行距离函数。结果应采用以下格式:

name1, name2, distance

我写了这样的距离函数:

dist <- function(a, b) sqrt((a$x-b$x)^2 + (a$y-b$y)^2)

我尝试使用outer函数,但它只需要向量,而不是数据表,我尝试在dplyr中使用各种连接但是不成功。

2 个答案:

答案 0 :(得分:7)

假设您的数据集如下所示:

d <- data_frame(name = rownames(mtcars), x = mtcars$mpg, y = mtcars$cyl)

尝试两个数据框的所有组合(或与其自身的所有组合)的一般方法是tidyr的crossing函数(尽管您需要注意重命名列)。之后,您将能够计算距离并进行过滤:

library(dplyr)
library(tidyr)

d %>%
  rename(name1 = name, x1 = x, y1 = y) %>%
  crossing(d) %>%
  rename(name2 = name, x2 = x, y2 = y) %>%
  mutate(distance = sqrt((x1 - x2) ^ 2 + (y1 - y2) ^ 2)) %>%
  filter(name1 != name2)

在这种特殊情况下,您可以使用我的fuzzyjoin包,特别是distance_join(您需要GitHub的最新开发版本)。这将根据距离阈值连接两个数据框(在本例中为自连接),并附加一个距离为的附加列:

library(fuzzyjoin)

d %>%
  rename(name1 = name) %>%
  distance_inner_join(d, max_dist = Inf, distance_col = "distance") %>%
  rename(name2 = name) %>%
  filter(name1 != name2)

这将给出:

# A tibble: 992 x 7
       name1   x.x   y.x             name2   x.y   y.y distance
       <chr> <dbl> <dbl>             <chr> <dbl> <dbl>    <dbl>
1  Mazda RX4    21     6     Mazda RX4 Wag  21.0     6 0.000000
2  Mazda RX4    21     6        Datsun 710  22.8     4 2.690725
3  Mazda RX4    21     6    Hornet 4 Drive  21.4     6 0.400000
4  Mazda RX4    21     6 Hornet Sportabout  18.7     8 3.047950
5  Mazda RX4    21     6           Valiant  18.1     6 2.900000
6  Mazda RX4    21     6        Duster 360  14.3     8 6.992138
7  Mazda RX4    21     6         Merc 240D  24.4     4 3.944617
8  Mazda RX4    21     6          Merc 230  22.8     4 2.690725
9  Mazda RX4    21     6          Merc 280  19.2     6 1.800000
10 Mazda RX4    21     6         Merc 280C  17.8     6 3.200000
# ... with 982 more rows

如果您知道自己并不关心远距离比赛,可以将max_dist设置为另一个非无限阈值。

答案 1 :(得分:3)

这是一个使用cbinddist(@mrflick提到的函数)的基本R方法。我们在这篇文章的底部创建了一个名为df的data.frame。

请注意,dist会返回一个下三角矩阵:

dist(df[,-1])
         1        2
2 1.414214         
3 2.236068 2.236068

我们可以使用combn创建名称变量的成对比较,然后将结果合并到data.frame中,并为列名称提供setNames

dfNew <- setNames(data.frame(t(combn(df$name, 2)),
                             combn(df$name, 2, function(i) {
                                                 dist(df[df$name %in% i, -1])})),
                  c("var1", "var2", "distance"))

返回

dfNew
      var1 var2 distance
    1    a    b 1.414214
    2    a    c 2.236068
    3    b    c 2.236068

请注意,names变量必须是字符,或者您必须将其包装在as.character函数中才能使其生效。

数据

df <- read.table(header=TRUE, text="name, x, y
a, 1, 2
b, 2, 3
c, 3, 1", sep=",", stringsAsFactors=F)