从单个列创建多个列并清理结果

时间:2016-02-04 13:50:25

标签: r split tidyr

我有一个这样的数据框:

foo=data.frame(Point.Type = c("Zero Start","Zero Start", "Zero Start", "3000rpm_10%_13barG_Sdsdsa_1.0_ss_Pww","3000rpm_10%_13barG_Sdsdsa_1.0_ss_Pww","3000rpm_10%_13barG_Sdsdsa_1.0_ss_Pww","Zero Stop","Zero Start"),
               Point.Value = c(NA,NA,NA,rnorm(3),NA,NA))

我想通过将第一列与分隔符_分开来添加三列,并仅保留分割后获得的数值。对于第一列不包含任何_的行,三个新列应为NA。我使用separate稍微接近了,但这还不够:

> library(tidyr) 
> bar = separate(foo,Point.Type, c("rpm_nom", "GVF_nom", "p0in_nom"), sep="_", remove = FALSE, extra="drop", fill="right")
> bar
                            Point.Type    rpm_nom GVF_nom p0in_nom Point.Value
1                           Zero Start Zero Start    <NA>     <NA>          NA
2                           Zero Start Zero Start    <NA>     <NA>          NA
3                           Zero Start Zero Start    <NA>     <NA>          NA
4 3000rpm_10%_13barG_Sdsdsa_1.0_ss_Pww    3000rpm     10%   13barG   -1.468033
5 3000rpm_10%_13barG_Sdsdsa_1.0_ss_Pww    3000rpm     10%   13barG    1.280868
6 3000rpm_10%_13barG_Sdsdsa_1.0_ss_Pww    3000rpm     10%   13barG    0.270126
7                            Zero Stop  Zero Stop    <NA>     <NA>          NA
8                           Zero Start Zero Start    <NA>     <NA>          NA

我不确定为什么我的数据框现在包含两种明显不同的NA,但is.na似乎都喜欢它们,所以我可以忍受它。但是,我有两种问题:

  1. 新列应至少为numeric,可能为integer。相反,它们是character,因为尾随rpm%barG。我怎么摆脱那些?
  2. Point.Type无法拆分时,rpm_nom应为NA,而是Zero StartZero Stop。更改fill=选项只会更改哪一个新列获得Zero Start / Zero Stop。相反,我希望他们三个都是NA。我该怎么办?
  3. 注意:我正在使用tidyr,但您当然不需要,如果您认为有更好的方法可以执行此操作。

2 个答案:

答案 0 :(得分:2)

您可以使用 dplyr

对列进行后处理
library(dplyr)
foo <- foo %>%
  separate(Point.Type, c("rpm_nom", "GVF_nom", "p0in_nom"), 
           sep="_", remove = FALSE, extra="drop", fill="right") %>%
  mutate_each(funs(as.numeric(gsub("[^0-9]","",.))), rpm_nom, GVF_nom, p0in_nom)

gsub("[^0-9]","",.) - 部分删除所有非数字字符。如果你想阻止删除小数点,你可以使用[^0-9.]而不是[^0-9](就像他的答案中使用的@PierreLafortune),但要注意这也是包括不是小数点的点。通过将其包装在as.numeric中,您可以将它们转换为数值,同时将空单元格转换为NA。这给出了以下结果:

> foo
                            Point.Type rpm_nom GVF_nom p0in_nom Point.Value
1                           Zero Start      NA      NA       NA          NA
2                           Zero Start      NA      NA       NA          NA
3                           Zero Start      NA      NA       NA          NA
4 3000rpm_10%_13barG_Sdsdsa_1.0_ss_Pww    3000      10       13  -1.2361145
5 3000rpm_10%_13barG_Sdsdsa_1.0_ss_Pww    3000      10       13  -0.8727960
6 3000rpm_10%_13barG_Sdsdsa_1.0_ss_Pww    3000      10       13   0.9685555
7                            Zero Stop      NA      NA       NA          NA
8                           Zero Start      NA      NA       NA          NA

或使用 data.table (由评论中的@DavidArenburg提供):

library(data.table)
setDT(foo)[, c("rpm_nom","GVF_nom","p0in_nom") := 
             lapply(tstrsplit(Point.Type, "_", fixed = TRUE)[1:3],
                    function(x) as.numeric(gsub("[^0-9]","",x)))
           ]

会得到类似的结果:

> foo
                             Point.Type Point.Value rpm_nom GVF_nom p0in_nom
1:                           Zero Start          NA      NA      NA       NA
2:                           Zero Start          NA      NA      NA       NA
3:                           Zero Start          NA      NA      NA       NA
4: 3000rpm_10%_13barG_Sdsdsa_1.0_ss_Pww -0.09255445    3000      10       13
5: 3000rpm_10%_13barG_Sdsdsa_1.0_ss_Pww  1.18581340    3000      10       13
6: 3000rpm_10%_13barG_Sdsdsa_1.0_ss_Pww  2.14475950    3000      10       13
7:                            Zero Stop          NA      NA      NA       NA
8:                           Zero Start          NA      NA      NA       NA

这样做的好处是foo通过引用更新。由于速度更快,内存效率更高,因此对于使用大型数据集尤为重要。

答案 1 :(得分:1)

使用base R,我们可以在必要时强制NA值并强制执行numeric类:

bar[-1] <- lapply(bar[-1], function(x) {
  is.na(x) <- grepl("Zero", x)
  as.numeric(gsub("[^0-9.]", "", x))})
#                             Point.Type rpm_nom GVF_nom p0in_nom Point.Value
# 1                           Zero Start      NA      NA       NA          NA
# 2                           Zero Start      NA      NA       NA          NA
# 3                           Zero Start      NA      NA       NA          NA
# 4 3000rpm_10%_13barG_Sdsdsa_1.0_ss_Pww    3000      10       13   0.3558397
# 5 3000rpm_10%_13barG_Sdsdsa_1.0_ss_Pww    3000      10       13   1.1454829
# 6 3000rpm_10%_13barG_Sdsdsa_1.0_ss_Pww    3000      10       13   0.2958815
# 7                            Zero Stop      NA      NA       NA          NA
# 8                           Zero Start      NA      NA       NA          NA

减少到一行(@Jaap):

bar[-1] <- lapply(bar[-1], function(x) as.numeric(gsub("[^0-9.]", "", x)))