使用字符串字符位置标识来创建新变量

时间:2015-08-21 08:02:40

标签: r string if-statement

所以我已经能够实现我想要的输出,但我确信可以使用string来实现更高效的代码。

让我们玩这个数据

set.seed(123)

A <- 1:100
type.a <- rnorm(100, mean=5000, sd=1433)
type.b <- rnorm(100, mean=5000, sd=1425)
type.c <- rnorm(100, mean=5000, sd=1125)
type.d <- rnorm(100, mean=5000, sd=1233)

df1 <- data.frame(A, type.a, type.b, type.c, type.d)

现在我们要为df1创建一个新变量,如果type(a:d)以数字1开头,我将使用此代码进行识别:

df1$Type_1 <- with(df1, ifelse((type.a < 2000 & type.a > 999)|(type.b < 2000 & type.c > 999)|
                                (type.c < 2000 & type.c > 999)|(type.d < 2000 & type.d > 999), 1,0))

或者类似地,这也是:

df1$type_1 <- with(df1, ifelse(type.a < 2000 & type.a > 999, 1,
                              ifelse(type.b < 2000 & type.c > 999, 1, 
                                     ifelse(type.c < 2000 & type.c > 999, 1,
                                             ifelse(type.d < 2000 & type.d > 999, 1,0)))))

现在我的问题分为两部分

如何使用string来查看type(a:d)的第一个数字来测试它是否等于我们的约束。 (在本例中等于1)

其次,我有四列以上的数据。因此,我不认为它是有效的我每次指定列名称。是否可以使用[,x:y]

然后代码用于创建9个新的数据列(即.type_1&amp; type_2 ... type_9 ),作为我们{{的第一个数字 1}}的范围为1:9

2 个答案:

答案 0 :(得分:1)

我们可以使用substr来提取字符串的第一个字符。由于有四列以type开头,我们可以使用grep来获取列的数字索引,我们使用lapply循环列,检查第一个字符是否等于1如果我们想知道是否至少有一个值满足条件,我们可以用any包装它。使用lapply会为每个list元素返回长度为1的list输出。因为我们需要二进制(0/1)而不是逻辑(FALSE / TRUE),所以我们可以用+包装来强制逻辑到二进制表示。

 indx <- grep('^type', colnames(df1))
 lapply(df1[indx], function(x) +(any(substr(x, 1, 1)==1)))

如果我们需要矢量输出

 vapply(df1[indx], function(x) +(any(substr(x, 1, 1)==1)), 1L)

答案 1 :(得分:1)

@akrun的优雅回答。我对你问题的第二部分感兴趣。特别是关于您将如何使用第一部分来创建您提到的新9列。我不知道我是否遗漏了某些东西,但不是每次都检查第一个元素是否匹配1,2,3等,你可以简单地捕获第一个元素。像这样:

library(dplyr)
library(tidyr)


set.seed(123)

A <- 1:100
type.a <- rnorm(100, mean=5000, sd=1433)
type.b <- rnorm(100, mean=5000, sd=1425)
type.c <- rnorm(100, mean=5000, sd=1125)
type.d <- rnorm(100, mean=5000, sd=1233)

df1 <- data.frame(A, type.a, type.b, type.c, type.d)


   df1 %>% 
  group_by(A) %>% 
  mutate_each(funs(substr(.,1,1))) %>%                     # keep first digit
  ungroup %>%
  gather(variable, type, -A) %>%                           # create combinations of rows and digits
  select(-variable) %>%
  mutate(type = paste0("type_",type),
         value = 1) %>%
  group_by(A,type) %>%                                     
  summarise(value = sum(value)) %>%                        # count how many times the row belongs to each type
  ungroup %>%
  spread(type, value, fill=0) %>%                          # create the new columns
  inner_join(df1, by="A") %>%                              # join back initial info
  select(A, starts_with("type."), starts_with("type_"))    # order columns


#     A   type.a   type.b   type.c   type.d type_1 type_2 type_3 type_4 type_5 type_6 type_7 type_8 type_9
# 1   1 4196.838 3987.671 7473.662 4118.106      0      0      1      2      0      0      1      0      0
# 2   2 4670.156 5366.059 6476.465 4071.935      0      0      0      2      1      1      0      0      0
# 3   3 7233.629 4648.464 4701.712 3842.782      0      0      1      2      0      0      1      0      0
# 4   4 5101.039 4504.752 5611.093 3702.251      0      0      1      1      2      0      0      0      0
# 5   5 5185.269 3643.944 4533.868 4460.982      0      0      1      2      1      0      0      0      0
# 6   6 7457.688 4935.835 4464.222 5408.344      0      0      0      2      1      0      1      0      0
# 7   7 5660.493 3881.511 4112.822 2516.478      0      1      1      1      1      0      0      0      0
# 8   8 3187.167 2623.183 4331.056 5261.372      0      1      1      1      1      0      0      0      0
# 9   9 4015.740 4458.177 6857.271 6524.820      0      0      0      2      0      2      0      0      0
# 10 10 4361.366 6309.570 4939.218 7512.329      0      0      0      2      0      1      1      0      0
# .. ..      ...      ...      ...      ...    ...    ...    ...    ...    ...    ...    ...    ...    ...

我们在开头有A列和B列的示例:

library(dplyr)
library(tidyr)


    set.seed(123)

    A <- 1:100
    B <- 101:200
    type.a <- rnorm(100, mean=5000, sd=1433)
    type.b <- rnorm(100, mean=5000, sd=1425)
    type.c <- rnorm(100, mean=5000, sd=1125)
    type.d <- rnorm(100, mean=5000, sd=1233)

    df1 <- data.frame(A,B, type.a, type.b, type.c, type.d)


    # work by grouping on A and B
df1 %>% 
  group_by(A,B) %>% 
  mutate_each(funs(substr(.,1,1))) %>%                
  ungroup %>%
  gather(variable, type, -c(A,B)) %>%                     
  select(-variable) %>%
  mutate(type = paste0("type_",type),
         value = 1) %>%
  group_by(A,B,type) %>%                                     
  summarise(value = sum(value)) %>% 
  ungroup %>%
  spread(type, value, fill=0) %>%                       
  inner_join(df1, by=c("A","B")) %>%                            
  select(A,B, starts_with("type."), starts_with("type_"))  


#     A   B   type.a   type.b   type.c   type.d type_1 type_2 type_3 type_4 type_5 type_6 type_7 type_8 type_9
# 1   1 101 4196.838 3987.671 7473.662 4118.106      0      0      1      2      0      0      1      0      0
# 2   2 102 4670.156 5366.059 6476.465 4071.935      0      0      0      2      1      1      0      0      0
# 3   3 103 7233.629 4648.464 4701.712 3842.782      0      0      1      2      0      0      1      0      0
# 4   4 104 5101.039 4504.752 5611.093 3702.251      0      0      1      1      2      0      0      0      0
# 5   5 105 5185.269 3643.944 4533.868 4460.982      0      0      1      2      1      0      0      0      0
# 6   6 106 7457.688 4935.835 4464.222 5408.344      0      0      0      2      1      0      1      0      0
# 7   7 107 5660.493 3881.511 4112.822 2516.478      0      1      1      1      1      0      0      0      0
# 8   8 108 3187.167 2623.183 4331.056 5261.372      0      1      1      1      1      0      0      0      0
# 9   9 109 4015.740 4458.177 6857.271 6524.820      0      0      0      2      0      2      0      0      0
# 10 10 110 4361.366 6309.570 4939.218 7512.329      0      0      0      2      0      1      1      0      0
# .. .. ...      ...      ...      ...      ...    ...    ...    ...    ...    ...    ...    ...    ...    ...

但是,在这种情况下,您应该注意到每行有一个A值。因此,为了定义行(以独特的方式),确实不需要B.因此,您可以像以前一样工作(当B不在那里时),只需将B加入您的结果:

df1 %>% 
      select(-B) %>%
      group_by(A) %>% 
      mutate_each(funs(substr(.,1,1))) %>%                 
      ungroup %>%
      gather(variable, type, -A) %>%                        
      select(-variable) %>%
      mutate(type = paste0("type_",type),
             value = 1) %>%
      group_by(A,type) %>%                                     
      summarise(value = sum(value)) %>%            # count how many times the row belongs to each type
      ungroup %>%
      spread(type, value, fill=0) %>%                          
      inner_join(df1, by="A") %>%                              
      mutate(B=B) %>%
      select(A,B, starts_with("type."), starts_with("type_"))