特定条件下字母/数字的所有组合

时间:2018-02-23 15:37:45

标签: r for-loop dataframe

我创建了这些载体:

Letters <- c("A","C","E","G","H","J","K")  
Numbers <- c(0,1,2,3,4,6,7,9) 
AlphaNumeric <- c(Letters, Numbers)

我希望在以下三个条件下使用上述所有元素接收所有3元素组合的数据帧(例如AA1,G26等):

1。)第一个元素是一个字母

2。)第二个元素是数字或SAME字母作为第一个元素

3.)第三个元素是数字

方法: 我尝试使用expand.grid()并成功设法获得包含3个元素的所有组合。然后我尝试expand.grid(x = Letters, y = AlphaNumeric, z = Numbers)并设法实现1.)和3.)但到目前为止未能管理2.)。

不满意的解决方案: 我已经找到了一种使用for循环执行此操作的方法,但我想除此之外必须有一种更简单的方法:

   LNN <- expand.grid(x = Letters, y = Numbers, z = Numbers)

   for ( Element in Letters) {
       currentLLN <- expand.grid(x = Element, y = Element, z = Numbers)
       LNN <- merge(LNN, currentLLN, all = TRUE)}

非常感谢任何帮助,谢谢你,Christian

4 个答案:

答案 0 :(得分:6)

您可以创建两个数据框,一个是第二个元素是数字,另一个是第二个元素与第一个元素相同,然后是rbind个。下面给出一个示例,请注意我为了说明目的限制了您的示例数据。

Letters <- LETTERS[1:3]  
Numbers <- c(1,2)

df1 = expand.grid(v1=Letters,v3=Numbers,stringsAsFactors = F)
df1$v2 = df1$v1
df1 = df1[,c('v1','v2','v3')]
df2 = expand.grid(v1=Letters,v2=as.character(Numbers),v3=Numbers, stringsAsFactors = F)
df = rbind(df1,df2)

输出:

> df
   v1 v2 v3
1   A  A  1
2   B  B  1
3   C  C  1
4   A  A  2
5   B  B  2
6   C  C  2
7   A  1  1
8   B  1  1
9   C  1  1
10  A  2  1
11  B  2  1
12  C  2  1
13  A  1  2
14  B  1  2
15  C  1  2
16  A  2  2
17  B  2  2
18  C  2  2

希望这有帮助!

虽然两个答案都运行得非常快,但Parfait的解决方案是解决问题的一个很好的解决方案,我当然不想诋毁他的答案,我认为最好指出创建额外的组合和子集将成为数据较大时的较大问题。基准测试如下所示。

Letters <- c(LETTERS[1:26],letters[1:4])
Numbers <- seq(30)
AlphaNumeric <- c(Letters, Numbers)


f_flo <- function()
{
  df1 = expand.grid(v1=Letters,v3=Numbers,stringsAsFactors = F)
  df1$v2 = df1$v1
  df1 = df1[,c('v1','v2','v3')]
  df2 = expand.grid(v1=Letters,v2=as.character(Numbers),v3=Numbers, stringsAsFactors = F)
  df = rbind(df1,df2)
}

f_parfait <- function()
{
  df <- expand.grid(x = Letters, y = AlphaNumeric, z = Numbers, stringsAsFactors = FALSE)
  sub <- subset(df,  (x == y | grepl("[0-9]", y)) &  grepl("[0-9]", z) )
  sub <- with(sub, sub[order(x, y, z),])   # SORT DATAFRAME
  rownames(sub) <- NULL                    # RESET ROWNAMES
}

library(dplyr)
one_letter <- function(l) {
  expand.grid(l, c(l, Numbers), Numbers, stringsAsFactors = FALSE)
}

f_stibu <- function(){
  df <- bind_rows(lapply(Letters, one_letter))
}


library(microbenchmark)
library(ggplot2)

run_times = microbenchmark(f_flo(),f_parfait(),f_stibu())
autoplot(run_times)

结果:

Unit: milliseconds
        expr        min         lq       mean     median         uq       max neval cld
     f_flo()   1.900719   2.047591   3.666935   2.314258   3.922053  78.74793   100  a 
 f_parfait() 138.028364 142.529904 152.876116 144.159444 146.835958 246.92318   100   b
   f_stibu()   4.130464   4.333130   5.169664   4.585028   6.209233  10.23139   100  a 

enter image description here

答案 1 :(得分:4)

只需将您的expand.grid()数据框与grepl个电话进行对:

df <- expand.grid(x = Letters, y = AlphaNumeric, z = Numbers, stringsAsFactors = FALSE)

sub <- subset(df,  (x == y | grepl("[0-9]", y)) )

sub <- with(sub, sub[order(x, y, z),])   # SORT DATAFRAME
rownames(sub) <- NULL                    # RESET ROWNAMES

head(sub, 10)    
#    x y z
# 1  A 0 0
# 2  A 0 1
# 3  A 0 2
# 4  A 0 3
# 5  A 0 4
# 6  A 0 6
# 7  A 0 7
# 8  A 0 9
# 9  A 1 0

答案 2 :(得分:3)

只需一个字母,问题很容易解决:第二列是该字母或任何数字,第三列是数字:

one_letter <- function(l) {
  expand.grid(l, c(l, Numbers), Numbers, stringsAsFactors = FALSE)
}

然后,您只需将该函数应用于每个字母,并将结果数据框合并为一个:

library(dplyr)
df <- bind_rows(lapply(Letters, one_letter))
head(df)
##   Var1 Var2 Var3
## 1    A    A    0
## 2    A    0    0
## 3    A    1    0
## 4    A    2    0
## 5    A    3    0
## 6    A    4    0

使用包dplyr是因为它提供了将数据帧列表组合到单个数据帧中的函数bind_rows()

答案 3 :(得分:1)

只使用前3个字母和前2个数字。然后您将获得以下结果:

> Numbers=c(0,1)
> Letters=c("A","C")
> A=outer(Letters,outer(Numbers,Numbers,paste0),paste0)
> B=outer(paste0(Letters,Letters),Numbers,paste0)
> sort(c(A,B))
 [1] "A00" "A01" "A10" "A11" "AA0" "AA1" "C00" "C01" "C10" "C11" "CC0" "CC1" "E00" "E01" "E10"
[16] "E11" "EE0" "EE1"