【问题标题】:Loop to Replace Matching Values循环替换匹配值
【发布时间】:2018-03-02 22:52:45
【问题描述】:

我正在寻找一种简单而优雅的方式来实现这一点。
所以如果我有数据集x 并且关系是A -> B -> Z -> YD -> H -> G,我想创建数据集y。不幸的是,它们不一定是有序的:

> x <- data.frame(
+     from = as.character(c("A", "E", "B", "D", "H", "Z")), 
+     to = as.character(c("B", "E", "Z", "H", "G", "Y")))
> 
> y <- data.frame(
+     from = as.character(c("A", "E", "B", "D", "H", "Z")), 
+     to = as.character(c("Y", "E", "Y", "G", "G", "Y")))
> 
> x
  from to
1    A  B
2    E  E
3    B  Z
4    D  H
5    H  G
6    Z  Y
> y
  from to
1    A  Y
2    E  E
3    B  Y
4    D  G
5    H  G
6    Z  Y


我有一个相当大的数据集(目前有 500k 行;将来会增长)并且实际上关心性能;我不确定是否有任何其他方法可以在没有 for 循环甚至矢量化/并行化过程的情况下执行此操作。
我正在考虑拆分和删除 from == to 处的所有行,或者创建一个指示器来跳过某些行,这样循环就不必每次都遍历整个数据集。
如果我确实创建了一个循环,我也想知道断点应该是什么;我不确定如何定义循环何时停止。
任何建议,将不胜感激。谢谢!

【问题讨论】:

  • 看起来像是igraph的案例
  • @akrun 以前从未听说过它,而且文档看起来相当庞大——您对从哪里开始查找或从哪个函数开始有什么建议吗?感谢您的建议!

标签: r loops for-loop


【解决方案1】:

我们可以使用dplyr通过比较'to'和'from'的相邻元素来创建分组变量,并将'to'中的值更改为'to'的last元素

library(dplyr)
x %>% 
    group_by(grp = cumsum(lag(lead(from, default = last(from)) != 
      as.character(to), default = TRUE))) %>% 
    mutate(to = last(to)) %>%
    ungroup %>%
    select(-grp)
# A tibble: 4 x 2
#  from   to    
# <fctr> <fctr>
#1 A      D     
#2 B      D     
#3 C      D     
#4 E      E    

【讨论】:

  • 我实际上是在看这个函数,但如果不看表格,我不知道最终结果 (y$to) 是“DDDE”,那么它是如何工作的?
  • @creativename 更新了帖子
  • 令人印象深刻!我喜欢 dplyr 解决方案。看来您知道cumsum 周围的方式:) 但我并不是要暗示它们总是按顺序排列-您能看看我更新的示例吗?
  • @creativename 谢谢,更新后的预期输出我不清楚
  • 很抱歉在原问题中没有说清楚;我试图创造一个更好的例子。一个关系仍然是A -&gt; B -&gt; C -&gt; D,但表格不一定按顺序排列。我刚刚添加了几行也来自F -&gt; G -&gt; H
【解决方案2】:

使用dplyr 中的lagtidyr 中的fill 可以实现另一种解决方案:

library(tidyverse)

x %>% arrange(from) %>%
  mutate(samegroup = ifelse(from == lag(to), 1, 0)) %>%
  mutate(group = ifelse(samegroup == 0 | is.na(samegroup), row_number(), NA)) %>%
  fill(group) %>%
  group_by(group) %>%
  mutate(to = last(to)) %>%
  ungroup() %>%
  select(-samegroup, - group)

# A tibble: 6 x 2
#  from  to   
#  <chr> <chr>
#1 A     D    
#2 B     D    
#3 C     D    
#4 E     E    
#5 F     H 
#6 G     H 

使用的数据

x <- data.frame(from = as.character(c("A", "B", "F", "C", "G", "E")), 
   to = as.character(c("B", "C", "G", "D", "H", "E")), 
   stringsAsFactors = FALSE)

【讨论】:

  • 似乎我的可重现示例中有很多缺陷来表示真实数据 - 我无法按“从”排列,因为它们不是按字母顺序排列的;我更新了这个例子。我同意否则这会起作用:(
  • @creativename 明白了。是的,我们需要寻找另一个逻辑。