2017-02-26 69 views
0

我想遍歷數據框中的列並將它們拆分爲基於分隔符的列。我使用的是tidyr::separate,這個功能一次只能處理一列。將tidyr ::分開放在多列上

例如:

df<- data.frame(a = c("5312,2020,1212"), b = c("345,982,284")) 

df <- separate(data = df, col = "a", 
         into = paste("a", c("col1", "col2", "col3"), 
             sep = "_"), sep = ",") 

返回:

a_col1 a_col2 a_col3   b 
1 5312 2020 1212 345,982,284 

當我嘗試過df R每次列執行相同的操作返回一個錯誤

例如我用這對迴路:

for(col in names(df)){ 
    df <- separate(data = df, col = col, 
into = paste(col, c("col1", "col2", "col3), 
sep = "_"), sep = ",") 
    } 

我期待得到以下的輸出:

a_col1 a_col2 a_col3 b_col1 b_col2 b_col3 
1 5312 2020 1212 345 982 284 

然而[R返回此錯誤:

Error in if (!after) c(values, x) else if (after >= lengx) c(x, values) else c(x[1L:after], : 
    argument is of length zero 

是否有一個數據幀申請tidyr::separate在多個列的另一種方式?

+0

'DF%>%聚集() %>%separate_rows(value)%>%mutate(key = paste0(key,'_col',1:3))%>%spread(key,value)',但這並不比調用'separate'兩次簡單。 – alistaire

+0

...或者你可以用SE'separate_'修飾你的原稿,例如'for(name in name(df))df < - separate_(df,name,into = paste0(name,'_col',1:3 ))',但那種風格讓我非常不安。 – alistaire

回答

1

您可以將定製的separate_()呼叫轉入Reduce()

sep <- function(...) { 
    dots <- list(...) 
    n <- stringr::str_count(dots[[1]][[dots[[2]]]], "\\d+") 
    separate_(..., into = sprintf("%s_col%d", dots[[2]], 1:n)) 
} 

df %>% Reduce(f = sep, x = c("a", "b")) 
# a_col_1 a_col_2 a_col_3 b_col_1 b_col_2 b_col_3 
# 1 5312 2020 1212  345  982  284 

否則,cSplit也會這樣做。

splitstackshape::cSplit(df, names(df)) 
#  a_1 a_2 a_3 b_1 b_2 b_3 
# 1: 5312 2020 1212 345 982 284 
+0

'splitstackshape :: cSplit'很有用。然而,'sep'函數有點令人困惑,它適用於給定的'df',但如果擴大到更大和不同的數據幀,它會失敗,這可能你已經知道了。 – spies006

0

我有相同的查詢(學習tidyverse),所以通過這樣的工作。注:我想要一個不會中斷的解決方案,所以不需要知道姓名。

library(tidyverse) 

創建輸入:

dft <- as_tibble(data.frame(a = c("5312,2020,1212"), b = c("345,982,284"))) 
df <- as.data.frame(dft) 

創建一個空白tibble收集輸出:

dft0 <- read_csv("a\na") 
dft0 <- dft0[,-1] 
dft00 <- dft0 

指定要分離的元素的長度(可以在迴路中完成,但我們知道從dft);注:如果一定要命名一個更好的方法,使用:

leng <- 3 

for循環版本:

for(x in 1:dim(df)[2]){ 
     dataCol <- dft[,x] 
     newCols <- paste(colnames(dataCol)[1], paste("col", 1:leng, sep="") , sep="_") 

     dft0 <- cbind(dft0, 
        separate(data = dataCol, 
          col = colnames(dataCol)[1], 
          into = newCols, 
          sep = ","))} 

凌亂sapply版本:

sapp <- sapply(colnames(df),function(ff){ 
          separate(as_tibble(df[,ff]), 
            "value", 
            letters[1:leng], 
            sep=",")}) 

dft00 <- as_tibble(do.call(cbind, sapp)) 

colnames(dft00) <- as.vector(sapply(colnames(sapp), 
          function(sa){ 
             paste(sa, 
              rownames(sapp), 
              sep="_") 
             }))