Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/r/65.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
比R中的嵌套for循环更有效的方法--匹配_R_For Loop_Apply - Fatal编程技术网

比R中的嵌套for循环更有效的方法--匹配

比R中的嵌套for循环更有效的方法--匹配,r,for-loop,apply,R,For Loop,Apply,我试图匹配名字、姓氏和名字相同的人,并保留ID的最小数值 我在下面创建了一个测试数据库(比我的实际数据集小得多),并编写了一个嵌套的for循环,看起来它正在做它应该做的事情 但在更大的数据集上,速度非常慢 我对应用函数比较陌生,但它们在应用函数方面似乎比数据争用更直观 对于我在这里做的事情,有什么更有效的替代方案?我相信有一个简单的解决办法,如果我在这里问这个问题,我会摇头,但我不会去问 dta.test<- NULL dta.test$Person_id <- c(1,2,3,4,

我试图匹配名字、姓氏和名字相同的人,并保留ID的最小数值

我在下面创建了一个测试数据库(比我的实际数据集小得多),并编写了一个嵌套的for循环,看起来它正在做它应该做的事情

但在更大的数据集上,速度非常慢

我对应用函数比较陌生,但它们在应用函数方面似乎比数据争用更直观

对于我在这里做的事情,有什么更有效的替代方案?我相信有一个简单的解决办法,如果我在这里问这个问题,我会摇头,但我不会去问

dta.test<- NULL
dta.test$Person_id <- c(1,2,3,4,5,6,7,8,9,10, 11)
dta.test$FirstName <- c("John", "James", "John", "Alex", "Alexander", "Jonathan", "John", "Alex", "James", "John", "John")
dta.test$LastName <- c("Smith", "Jones", "Jones", "Jones", "Jones", "Smith", "Jones", "Smith", "Johnson", "Smith", "Smith")
dta.test$DOB <- c("2001-01-01", "2002-01-01", "2003-01-01", "2004-01-01", "2004-01-01", "2001-01-01", "2003-01-01", "2006-01-01", "2006-01-01", "2001-01-01", "2009-01-01")
dta.test$Actual_ID <- c(1, 2, 3, 4, 5, 6, 3, 8, 9, 1, 11)
dta.test <- as.data.frame(dta.test)

for(i in unique(dta.test$FirstName))
  for(j in unique(dta.test$LastName))
    for (k in unique (dta.test$DOB))
{
  {
    {
       dta.test$Person_id[dta.test$FirstName==i & dta.test$LastName==j & dta.test$DOB==k] <- min(dta.test$Person_id[dta.test$FirstName==i & dta.test$LastName==j & dta.test$DOB==k], na.rm=T)
    }
  }
}

dta.test这里有一个
dplyr
解决方案

library(dplyr)
dta.test %>%
  group_by(FirstName, LastName, DOB) %>%
  mutate(Person_id = min(Person_id))

# A tibble: 11 x 5
# Groups: FirstName, LastName, DOB [9]
   # Person_id FirstName LastName DOB        Actual_ID
       # <dbl> <fct>     <fct>    <fct>          <dbl>
 # 1        1. John      Smith    2001-01-01        1.
 # 2        2. James     Jones    2002-01-01        2.
 # 3        3. John      Jones    2003-01-01        3.
 # 4        4. Alex      Jones    2004-01-01        4.
 # 5        5. Alexander Jones    2004-01-01        5.
 # 6        6. Jonathan  Smith    2001-01-01        6.
 # 7        3. John      Jones    2003-01-01        3.
 # 8        8. Alex      Smith    2006-01-01        8.
 # 9        9. James     Johnson  2006-01-01        9.
# 10        1. John      Smith    2001-01-01        1.
# 11       11. John      Smith    2009-01-01       11.
库(dplyr)
dta.test%>%
分组人(名字、姓氏、出生日期)%>%
变异(Person_id=min(Person_id))
#A tibble:11 x 5
#组:名字、姓氏、出生日期[9]
#人员id名字姓氏DOB实际id
#                     
# 1        1. 约翰·史密斯2001-01-01 1。
# 2        2. 詹姆斯·琼斯2002-01-01 2。
# 3        3. 约翰·琼斯2003-01-01 3。
# 4        4. 亚历克斯·琼斯2004-01-01 4。
# 5        5. 亚历山大·琼斯2004-01-01 5。
# 6        6. 乔纳森·史密斯2001-01-01 6。
# 7        3. 约翰·琼斯2003-01-01 3。
# 8        8. 亚历克斯·史密斯2006-01-01 8。
# 9        9. 詹姆斯·约翰逊2006-01-01 9。
# 10        1. 约翰·史密斯2001-01-01 1。
# 11       11. 约翰·史密斯2009-01-01 11。
编辑-添加性能比较

for_loop_approach <- function() {
    for(i in unique(dta.test$FirstName))
      for(j in unique(dta.test$LastName))
        for (k in unique (dta.test$DOB))
    {
      {
        {
           dta.test$Person_id[dta.test$FirstName==i & dta.test$LastName==j & dta.test$DOB==k] <- min(dta.test$Person_id[dta.test$FirstName==i & dta.test$LastName==j & dta.test$DOB==k], na.rm=T)
        }
      }
    }
}

dplyr_approach <- function() {
    require(dplyr)
    dta.test %>%
      group_by(FirstName, LastName, DOB) %>%
      mutate(Person_id = min(Person_id))
}

library(microbenchmark)
microbenchmark(for_loop_approach(), dplyr_approach(), unit="relative", times=100L)

Unit: relative
                expr      min      lq    mean   median       uq      max neval
 for_loop_approach() 20.97948 20.6478 18.8189 17.81437 17.91815 11.76743   100
    dplyr_approach()  1.00000  1.0000  1.0000  1.00000  1.00000  1.00000   100
There were 50 or more warnings (use warnings() to see the first 50)

for_loop_方法这里有一个
dplyr
解决方案

library(dplyr)
dta.test %>%
  group_by(FirstName, LastName, DOB) %>%
  mutate(Person_id = min(Person_id))

# A tibble: 11 x 5
# Groups: FirstName, LastName, DOB [9]
   # Person_id FirstName LastName DOB        Actual_ID
       # <dbl> <fct>     <fct>    <fct>          <dbl>
 # 1        1. John      Smith    2001-01-01        1.
 # 2        2. James     Jones    2002-01-01        2.
 # 3        3. John      Jones    2003-01-01        3.
 # 4        4. Alex      Jones    2004-01-01        4.
 # 5        5. Alexander Jones    2004-01-01        5.
 # 6        6. Jonathan  Smith    2001-01-01        6.
 # 7        3. John      Jones    2003-01-01        3.
 # 8        8. Alex      Smith    2006-01-01        8.
 # 9        9. James     Johnson  2006-01-01        9.
# 10        1. John      Smith    2001-01-01        1.
# 11       11. John      Smith    2009-01-01       11.
库(dplyr)
dta.test%>%
分组人(名字、姓氏、出生日期)%>%
变异(Person_id=min(Person_id))
#A tibble:11 x 5
#组:名字、姓氏、出生日期[9]
#人员id名字姓氏DOB实际id
#                     
# 1        1. 约翰·史密斯2001-01-01 1。
# 2        2. 詹姆斯·琼斯2002-01-01 2。
# 3        3. 约翰·琼斯2003-01-01 3。
# 4        4. 亚历克斯·琼斯2004-01-01 4。
# 5        5. 亚历山大·琼斯2004-01-01 5。
# 6        6. 乔纳森·史密斯2001-01-01 6。
# 7        3. 约翰·琼斯2003-01-01 3。
# 8        8. 亚历克斯·史密斯2006-01-01 8。
# 9        9. 詹姆斯·约翰逊2006-01-01 9。
# 10        1. 约翰·史密斯2001-01-01 1。
# 11       11. 约翰·史密斯2009-01-01 11。
编辑-添加性能比较

for_loop_approach <- function() {
    for(i in unique(dta.test$FirstName))
      for(j in unique(dta.test$LastName))
        for (k in unique (dta.test$DOB))
    {
      {
        {
           dta.test$Person_id[dta.test$FirstName==i & dta.test$LastName==j & dta.test$DOB==k] <- min(dta.test$Person_id[dta.test$FirstName==i & dta.test$LastName==j & dta.test$DOB==k], na.rm=T)
        }
      }
    }
}

dplyr_approach <- function() {
    require(dplyr)
    dta.test %>%
      group_by(FirstName, LastName, DOB) %>%
      mutate(Person_id = min(Person_id))
}

library(microbenchmark)
microbenchmark(for_loop_approach(), dplyr_approach(), unit="relative", times=100L)

Unit: relative
                expr      min      lq    mean   median       uq      max neval
 for_loop_approach() 20.97948 20.6478 18.8189 17.81437 17.91815 11.76743   100
    dplyr_approach()  1.00000  1.0000  1.0000  1.00000  1.00000  1.00000   100
There were 50 or more warnings (use warnings() to see the first 50)

for_loop_方法我实施了一种基本R方法,而不是dplyr方法,结果(根据microbenchmark)比CPak的dplyr方法快7.46倍,比for loop方法快139.4倍。我刚刚使用了
match
paste0
函数来实现此功能,它将自动保留最小的匹配id:

  dta.test[, "Actual_id"] <- match(paste0(dta.test$FirstName, dta.test$LastName, dta.test$DOB), paste0(dta.test$FirstName, dta.test$LastName, dta.test$DOB))
在您的真实数据中,我希望person id不是那么简单(不仅仅是一个整数),并且不按数字顺序运行,例如

dta.test$Person_id <- paste0(LETTERS[1:11],1:11)
给予:

   Person_id FirstName LastName        DOB Actual_id
1         A1      John    Smith 2001-01-01        A1
2         B2     James    Jones 2002-01-01        B2
3         C3      John    Jones 2003-01-01        C3
4         D4      Alex    Jones 2004-01-01        D4
5         E5 Alexander    Jones 2004-01-01        E5
6         F6  Jonathan    Smith 2001-01-01        F6
7         G7      John    Jones 2003-01-01        C3
8         H8      Alex    Smith 2006-01-01        H8
9         I9     James  Johnson 2006-01-01        I9
10       J10      John    Smith 2001-01-01        A1
11       K11      John    Smith 2009-01-01       K11

我已经实现了一种基本R方法,而不是dplyr方法,它比CPak的dplyr方法快7.46倍,比for-loop方法快139.4倍。我刚刚使用了
match
paste0
函数来实现此功能,它将自动保留最小的匹配id:

  dta.test[, "Actual_id"] <- match(paste0(dta.test$FirstName, dta.test$LastName, dta.test$DOB), paste0(dta.test$FirstName, dta.test$LastName, dta.test$DOB))
在您的真实数据中,我希望person id不是那么简单(不仅仅是一个整数),并且不按数字顺序运行,例如

dta.test$Person_id <- paste0(LETTERS[1:11],1:11)
给予:

   Person_id FirstName LastName        DOB Actual_id
1         A1      John    Smith 2001-01-01        A1
2         B2     James    Jones 2002-01-01        B2
3         C3      John    Jones 2003-01-01        C3
4         D4      Alex    Jones 2004-01-01        D4
5         E5 Alexander    Jones 2004-01-01        E5
6         F6  Jonathan    Smith 2001-01-01        F6
7         G7      John    Jones 2003-01-01        C3
8         H8      Alex    Smith 2006-01-01        H8
9         I9     James  Johnson 2006-01-01        I9
10       J10      John    Smith 2001-01-01        A1
11       K11      John    Smith 2009-01-01       K11

数据表解决方案可能是处理包含大量组的大型数据最快的解决方案:

library(data.table)
setDT(dta.test, key = c("FirstName", "LastName", "DOB"))
dta.test[, Actual_ID := min(Person_id, na.rm = TRUE), by = .(FirstName, LastName, DOB)]

数据表解决方案可能是处理包含大量组的大型数据最快的解决方案:

library(data.table)
setDT(dta.test, key = c("FirstName", "LastName", "DOB"))
dta.test[, Actual_ID := min(Person_id, na.rm = TRUE), by = .(FirstName, LastName, DOB)]

我刚把它打出来,+1完美。谢谢明显地更加清晰和简洁。但是性能的提高是什么?为什么?我只是在输入+1完美。谢谢明显地更加清晰和简洁。但是性能改进是什么?为什么?
match
将进行第一场比赛,而不是最低限度的比赛。由于OP明确表示他们希望保留“最小的数值”,所以您应该首先进行排序。(为了进行公平比较,您可能应该在基准测试中包括排序时间,因为其他解决方案不需要排序输入。)注意,添加排序后,它仍然比第一次匹配快4倍,而不是最小值。由于OP明确表示他们希望保留“最小的数值”,所以您应该首先进行排序。(为了进行公平比较,您可能应该在基准测试中包括排序时间,因为其他解决方案不需要排序输入。)注意,添加排序后,排序速度仍然快4倍