【问题标题】:matching values across columns跨列匹配值
【发布时间】:2016-10-28 19:26:27
【问题描述】:

假设我有一个数据框,我想查看给定列中的每个给定值是否等于第二列下一行中的值?

我可以在 1 场比赛中做到这一点,但我正在尝试为整个数据框做到这一点:

 match(dataset$co1[i], dataset$co1[i+1]) # where i is a given row #

测试数据集:

case <- c("A", "B", "C", "A", "A", "A" ,"B", "C", "B", "A")
col1 <- c(1, 100, 50, 600, 29, 72, 7, 64, 15, 85)
col2 <- c(600, 7, 64, 29, 57, 85, 12, 82, 71, 34)
dataset <- data.frame(case, col1, col2)

我也想这样做。我试图查看是否可以将匹配行放在 by 语句中,但我很难弄清楚如何沿列建立索引。

有什么建议吗?

【问题讨论】:

  • 我对示例的预期输出感到困惑。这里没有可以找到匹配项的行,对吧?
  • 你是说match(dataset$col1[i], dataset$col2[i+1])对吧?
  • 如果您觉得有帮助,请不要忘记接受答案:)

标签: r dataframe match


【解决方案1】:

正如@Frank 指出的那样,根据您的匹配条件和您提供的数据集,不会有任何匹配项。因此,出于演示目的,我修改了您的数据集以表明我的解决方案确实有效。下面是一个使用 dplyr 的简单方法:

# Modified dataset
case <- c("A", "B", "C", "A", "A", "A" ,"B", "C", "B", "A")
col1 <- c(1, 100, 50, 600, 29, 72, 7, 64, 15, 85)
col2 <- c(600, 7, 64, 1, 600, 85, 100, 82, 71, 34)
dataset <- data.frame(case, col1, col2)
> dataset
   case col1 col2
1     A    1  600
2     B  100    7
3     C   50   64
4     A  600    1
5     A   29  600
6     A   72   85
7     B    7  100
8     C   64   82
9     B   15   71
10    A   85   34

请注意,我将 col2 的第 4 行更改为 1,将第 5 行更改为 600,将第 7 行更改为 100。这样 col2 的第 4 行将与 col1 的第 1 行匹配,col2 的第 5 行与 col1 的第 4 行匹配,并且按大小写匹配时,col2 的第 7 个与 col1 的第 2 个匹配。此外,当 not 按大小写匹配时,只有 col2 的第 5 行会与 col1 的第 4 行匹配。

library(dplyr)
dataset %>% 
  add_rownames() %>%
  mutate(col2 = lead(col2)) %>%
  filter(col1 == col2)

# A tibble: 1 × 4
  rowname   case  col1  col2
    <chr> <fctr> <dbl> <dbl>
1       4      A   600   600

此代码返回与 col2 的下一行匹配的 col1 的行。我添加了add_rownames(),以便您知道它在dataset 中的原始行索引。 mutate() 中的 lead() 函数与 dplyr 中的 lag() 完全相反(基础 R 中的通用 lag() 不允许滞后非时间序列向量)。它“落后” col2 k = -1

dataset %>% 
  add_rownames() %>%
  group_by(case) %>%
  mutate(col2 = lead(col2)) %>%
  filter(col1 == col2)

Source: local data frame [3 x 4]
Groups: case [2]

  rowname   case  col1  col2
    <chr> <fctr> <dbl> <dbl>
1       1      A     1     1
2       2      B   100   100
3       4      A   600   600

通过添加group_by(),您可以做同样的事情,但要使用“大小写”。如您所见,它按预期返回匹配的行。

如果您出于某种原因不想使用dplyr,这里有一个更通用的解决方案:

## No group by case
# Lag col2 (Call the lagged column col3)
dataset$col3 = c(dataset$col2[-1], NA)

dataset$match = mapply(function(x, y) match(x, y, nomatch = FALSE), 
                       dataset$col1, dataset$col3)

> dataset[dataset$match == 1,]
  case col1 col2 col3 match
4    A  600    1  600     1

## Group by case
# Split dataset into groups
dataList = split(dataset, case)

dataMatched = lapply(dataList, function(x){
  x$col2 = c(x$col2[-1], NA)
  x$match = mapply(function(x, y) match(x, y, nomatch = FALSE), 
            x$col1, x$col2)
  return(x)
})

结果列表/数据框:

> dataMatched
$A
   case col1 col2 match
1     A    1    1     1
4     A  600  600     1
5     A   29   85     0
6     A   72   34     0
10    A   85   NA     0

$B
  case col1 col2 match
2    B  100  100     1
7    B    7   71     0
9    B   15   NA     0

$C
  case col1 col2 match
3    C   50   82     0
8    C   64   NA     0

> unsplit(dataMatched, case)
   case col1 col2 match
1     A    1    1     1
2     B  100  100     1
3     C   50   82     0
4     A  600  600     1
5     A   29   85     0
6     A   72   34     0
7     B    7   71     0
8     C   64   NA     0
9     B   15   NA     0
10    A   85   NA     0

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-01-21
    • 1970-01-01
    • 2018-03-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-11-01
    相关资源
    最近更新 更多