2013-07-18 40 views
1

我有一個data.frame,其中包含句點的字符串列,例如「a.b.c.X」。我想按時間段分割字符串並保留第三個分段,例如在給出的例子中「c」。這是我正在做的。如何正確操縱R中數據框中的字符串列?

> df = data.frame(v=c("a.b.a.X", "a.b.b.X", "a.b.c.X"), b=seq(1,3)) 
> df 
     v b 
1 a.b.a.X 1 
2 a.b.b.X 2 
3 a.b.c.X 3 

而且我要的是

> df = data.frame(v=c("a.b.a.X", "a.b.b.X", "a.b.c.X"), b=seq(1,3)) 
> df 
     v b 
1 a 1 
2 b 2 
3 c 3 

我試圖使用within,但我發現了奇怪的結果。第一列第一行的值正在重複。

> get = function(x) { unlist(strsplit(x, "\\."))[3] } 
> within(df, v <- get(as.character(v))) 
    v b 
1 a 1 
2 a 2 
3 a 3 

這樣做的最佳做法是什麼?我究竟做錯了什麼?


更新: 這是我從@ agstudy的回答中使用的解決方案:

> df = data.frame(v=c("a.b.a.X", "a.b.b.X", "a.b.c.X"), b=seq(1,3)) 
> get = function(x) gsub(".*?[.].*?[.](.*?)[.].*", '\\1', x) 
> within(df, v <- get(v))                                        
    v b 
1 a 1 
2 b 2 
3 c 3 

回答

2

使用一些正則表達式,你可以這樣做:

gsub(".*?[.].*?[.](.*?)[.].*", '\\1', df$v) 
[1] "a" "b" "c" 

或者更簡潔:

gsub("(.*?[.]){2}(.*?)[.].*", '\\2', v) 
+0

正則表達式總是要求我做一些思考,所以當別人去思考時,我會欣賞它。 +1 –

+0

@TylerRinker謝謝,雖然我在這個懶惰:)(懶惰貪心) – agstudy

+0

@agstudy謝謝!我一直在努力尋找正確的方法來在R中使用正則表達式來實現我想要的功能。以前我在使用R導入數據之前先在perl中進行轉換,但是我知道必須有一種方法可以在R中執行。這是更快,'strsplit/unlist'或'gsub'? – drsnyder

2

的問題是不是與within但你get功能。它返回一個字符("a"),當添加到data.frame時它會被回收。您的代碼應該是這樣的:

get.third <- function(x) sapply(strsplit(x, "\\."), `[[`, 3) 
within(df, v <- get.third(as.character(v))) 
+0

感謝您的快速反應。在這種情況下使用'strsplit' +'unlist'和'sapply'有什麼區別?特別是爲什麼'get'的返回值被循環使用,而不是單獨應用於數據框中的每一行? – drsnyder

2

這裏是一個可能的解決方案:

df[, "v"] <- do.call(rbind, strsplit(as.character(df[, "v"]), "\\."))[, 3] 

## > df 
## v b 
## 1 a 1 
## 2 b 2 
## 3 c 3 
0

的回答「我在做什麼錯」是的代碼,您認爲該位被提取第三每個分割字符串的元素實際上是把所有的字符串在一個單一的矢量所有的元素,然後返回的第三要素:

get = function(x) { 
    splits = strsplit(x, "\\.") 
    print("All the elements: ") 
    print(unlist(splits)) 
    print("The third element:") 
    print(unlist(splits)[3]) 
    # What you actually wanted: 
    third_chars = sapply(splits, function (x) x[3]) 
} 
within(df, v2 <- get(as.character(v)))