仅使用应用和子中断提取字符串列的数字部分

时间:2019-04-10 09:33:07

标签: r

我在R中有一个数据帧dat,看起来像这样:

id  x   y                           z
1   0   4 California                15 MSG 2017/11
2   0   1 Nationally Representative 11 MSG 2016/04
3   1   1 Nationally Representative 8 MSG 2016/01
4   0   1 Nationally Representative 1 ASDE 2014/01
5   2   1 Nationally Representative 8 MSG 2016/01
6   0   1 Nationally Representative 5 MSG 2015/07

现在,我想遍历每列,仅将数字部分保留在开头,例如在第一行中,变量x,我要保留“ 4”,变量z,我要保留“ 15”,依此类推。

我尝试了以下操作(即在每列中搜索空格字符并将其+空格后的部分删除):

dat_new = apply(dat, 2, function(x) sub(" .+", "", x)) # searchs for any space and deletes the space + everything after the space
dat_new = as.data.frame(apply(dat_new, 2, as.numeric))

但是,对于一小部分数据(例如前六行)有效的方法最终会中断。也就是说,我的数据框总共有5100行,应用上述函数会导致第一列(“ id”)变空,其他一些列也会发生这种情况。我目前找到了一种使用实际的for循环的解决方法,但仍想检查我的代码有什么问题以及是否还有其他优雅的解决方案。

dat的数据类型是:

'data.frame':   5109 obs. of  4 variables:
 $ id: int  1 2 3 4 5 6 7 8 9 10 ...
 $ x : int  0 0 1 0 2 0 1 1 0 0 ...
 $ y : Factor w/ 4 levels "1 Nationally Representative",..: 4 1 1 1 1 1 1 4 1 3 ...
 $ z : Factor w/ 16 levels "1 ASDE 2014",..: 7 3 15 1 15 12 12 8 13 5 ...

3 个答案:

答案 0 :(得分:1)

我们可以在“ y”,“ z”列上使用parse_number中的readr来提取第一组数字子字符串

library(dplyr)
library(readr)
dat %>%
      mutate_at(vars(y:z), list(~ parse_number(as.character(.))))
#  d x y  z
#1 1 0 4 15
#2 2 0 1 11
#3 3 1 1  8
#4 4 0 1  1
#5 5 2 1  8
#6 6 0 1  5

另一种选择是从空格中删除子字符串,然后转换为numeric

library(stringr)
dat %>% 
    mutate_at(vars(y:z), list(~ as.numeric(str_remove(., "\\s+.*"))))

或者使用base R,我们删除空格后跟其他字符,然后将第一个以外的列转换为数字

dat[-1] <- lapply(dat[-1], function(x) as.numeric(sub("\\s+.*", "", x)))

数据

dat <- structure(list(d = 1:6, x = c(0L, 0L, 1L, 0L, 2L, 0L), y = structure(c(2L, 
 1L, 1L, 1L, 1L, 1L), .Label = c("1 Nationally Representative", 
 "4 California"), class = "factor"), z = structure(c(3L, 2L, 5L, 
 1L, 5L, 4L), .Label = c("1 ASDE 2014/01", "11 MSG 2016/04", "15 MSG 2017/11", 
  "5 MSG 2015/07", "8 MSG 2016/01"), class = "factor")), row.names = c(NA, 
  -6L), class = "data.frame")

答案 1 :(得分:1)

使用基数R,我们可以lapply在选定的列上并提取数字部分

cols <- c("y", "z")
df[cols] <- lapply(df[cols], function(x) as.numeric(sub("(^\\d+).*", "\\1", x)))

df
#  id x y  z
#1  1 0 4 15
#2  2 0 1 11
#3  3 1 1  8
#4  4 0 1  1
#5  5 2 1  8
#6  6 0 1  5

答案 2 :(得分:1)

apply实现(可能会很慢):

as.data.frame(apply(dat,2,function(x) gsub("[A-Z].*","",x)))
  d x  y   z
1 1 0 4  15 
2 2 0 1  11 
3 3 1 1   8 
4 4 0 1   1 
5 5 2 1   8 
6 6 0 1   5