我在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 ...
答案 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