R:具有重复值的循环

时间:2011-05-23 04:03:24

标签: r while-loop

我正在尝试编写一个循环来搜索data.frame Bdate_B[j])中的正确日期,并将相关值X_B[j]复制到{{1与同一日期X_A[i]相关的变量。

挑战在于:a)目标data.frame date_A[i]有几个相同的日期,但b)没有系统地所有data.frame(B)的日期。 (B)包括所有需要的日期。因此,数据帧具有不同的长度。

问题:

  1. 为什么以下循环不起作用,但不返回错误消息?
  2. 如何解决?
  3. R?还有其他方法可以解决这个问题吗?
  4. 数据框为:

    A

    我的目标是:

        A =
    
             date_A         X_A 
        1    2010-01-01       
        2    2010-01-02
        3    2010-01-03
        4    2010-01-02
        5    2010-02-03
        6    2010-01-01
        7    2010-01-02
        .
        .
        . 
        20000
    
        B= 
    
             date_B           X_B
        1    2010-01-01       7.9
        2    2010-01-02       8.5
        3    2010-01-03       2.1
        .
        .
        400
    

    我编写了以下循环,但由于某种原因,它没有找到超越第一行的方式。换句话说,它不会更改其他 A= date_A X_A 1 2010-01-01 7.9 2 2010-01-02 8.5 3 2010-01-03 2.1 4 2010-01-02 8.5 5 2010-02-03 2.1 6 2010-01-01 7.9 7 2010-01-02 8.5 单元格的值,尽管循环会无休止地运行。

    X_A

    感谢您的帮助。

3 个答案:

答案 0 :(得分:7)

有了这种问题,merge会让事情变得更容易。以你的例子我没有与第七行匹配,但也许你有一个错字。我的A数据框只有date_A列。如果您想重命名X_B列,那么names()<-将轻松完成;

 merge(A, B, by.x=1, by.y=1, all.x=TRUE)
#---result---
      date_A X_B
1 2010-01-01 7.9
2 2010-01-01 7.9
3 2010-01-02 8.5
4 2010-01-02 8.5
5 2010-01-02 8.5
6 2010-01-03 2.1
7 2010-02-03  NA

答案 1 :(得分:2)

有了这些数据:

A <- data.frame( date_A = c('2010-01-01', '2010-01-02', '2010-01-03', '2010-01-02',
    '2010-02-03', '2010-01-01', '2010-01-02') )

B <- data.frame(   
    date_B = c('2010-01-01','2010-01-02','2010-01-03'),
    X_B = c(7.9,8.5,2.1))

您可以使用match()按正确的顺序索引X_B值:

A$X_A <- B$X_B[match(A$date_A,B$date_B)]

match()返回B$date_BA$date_A位置的索引。另一个使用的技巧是使用因子的级别作为索引:

A$X_A <- B$X_B[A$date_A]

这是有效的,因为每个因子都按排序顺序排列,并对应于数值(1,2,3 ...)。因此,如果B根据这些级别排序,则返回正确的索引。 (您可能希望对B进行排序以确保:B <- B[order(B$date_B),]


至于为什么循环不起作用。首先,我认为你真的不想在R脚本中使用;。它使代码更难阅读。最好的是如果你学会编写清晰的代码。在您的代码中,您可以使用更一致的分配器并使用正确的缩进。例如:

i <- 1
j <- 1
while (i <= nrow(A))
{
    while (j <= nrow(B))
    {
        if (A$date_A[i]==B$date_B[j]) A$X_A[i] <- B$X_B[j]
        j <- j+1
        if (j == nrow(B)) i <- i+1
        j <- 1
    }
}

这是你的代码,但阅读起来要清楚得多。对我来说,这不会运行,因为级别不可比(由于拼写错误)所以我进行了as.character()调用。在真实数据集中可能不需要这样做。

索引会立即显示最大问题:您在j <- 1部分之外放错了if (j == nrow(B))。使用;终止该行,从而终止条件部分。因为这个j在每个循环中都设置为1。

更改它会使其运行得更好,但是仍然会出现错误,因为while的{​​{1}}循环可能在j大于{{1}中的行数之前完成}}。这可以通过设置i语句并将A个循环折叠为一个来更改。最后,您需要将AND语句设置为大于while中的行数,或者省略一行。这应该有效:

if

但这只是为了表明出了什么问题,我从来没有建议这样做过这样的事情。即使你真的想要使用循环,你也可能更适合使用B循环。

答案 2 :(得分:2)

哇!你的代码让我害怕。至少,为这种事情使用for循环(虽然@Dwin的解决方案是解决这个问题的方法):

for(i in seq(nrow(A)))
{
    for(j in seq(nrow(B)))
    {
        if(A$date_A[i]==B$date_B[j])
        {
            A$X_A[i] <- B$X_B[j]
        }
    }
}

这样可以防止在while循环结束时手动尝试增加的所有丑陋(在你自己的代码中,顺便说一下,j = 1需要移到内括号之外)。

注意:此代码与您的代码一样,当B包含两行与A中的日期相同时,它不会解决问题(它将始终使用B中该行日期的最后一行的值)。它可以帮助您理解而不是简单的增量循环。