2016-02-04 29 views
2

我有這樣一個數據幀:從單個列創建多個列和清理結果

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。我怎樣才能做到這一點?

注意:我使用的是tidyr,但當然如果您認爲有更好的方法可以做到這一點,您當然不需要。

回答

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]","",.) -part刪除所有非數字字符。如果你想防止刪除小數點,你可以可以使用[^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已更新 引用。由於速度更快,內存效率更高,這對於使用大型數據集尤其有用。

+0

@Jaap聽起來不錯!是否可以通過使用'%>%'來避免創建'bar'? – DeltaIV

+0

@DavidArenburg你的解決方案看起來不錯,但data.table是什麼?我所有的代碼都適用於data.frames。我擔心切換到這些數據表可能會影響我的其他代碼。此外,我不知道函數'tstrsplit',但我想這是'data.table'包中記錄。 – DeltaIV

+1

@DeltaIV更新了答案。 'data.table'是'data.frame'的增強形式。有關更多信息,請參閱[此網頁](https://github.com/Rdatatable/data.table/wiki)。 – Jaap

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))) 
+0

我不確定你爲什麼使用'bar [-1]'。另外,@Jaap'gsub(「[^ 0-9]」,「」,x)'和你的'gsub(「[[:alpha:]] | [[:punct:]]」有什麼區別, 「,x)'?最後,爲什麼在你的最後一列你得到10^14量級的Point.Value? 'rnorm(3)'應該產生更接近於0的數字。 – DeltaIV

+0

'bar [-1]'移除我們不想處理的第一列。兩個正則表達式模式的區別可以在這裏看到http://www.cheatography.com/davechild/cheat-sheets/regular-expressions/。在最後一列中,小數點被刪除。 –