是否可以合并R data.frame中的行?

时间:2016-11-01 15:32:38

标签: r string dataframe merge

如果我有以下data.frame:

> df <- data.frame(x = c('a', 'b*', 'c'), y = c('d', 'e', 'f'))
> df
   x y
1  a d
2 b* e
3  c f

是否有明确的方法来标识df$x条目包含字符串值*的行,然后使用此条件强制将该行的字符串条目与其前面的行合并,产生如下的data.frame:

> df
     x   y
1 a b* d e
2    c   f

我假设问题的第一部分(标识包含`*的x行值)可以使用正则表达式以相当简单的方式完成。我无法确定如何强制data.frame行与其前面的行合并。

一个特别棘手的挑战是连续多个条目是否具有模式,例如

> df <- data.frame(x = c('a', 'b*', 'c*'), y = c('d', 'e', 'f'))
> df
   x y
1  a d
2 b* e
3 c* f

在这种情况下,生成的data.frame应如下所示:

> df
        x     y
1 a b* c* d e f

我发现的主要问题是,在运行一个循环的迭代后,将df[2,]的字符串粘贴到df[1,],data.frame索引不适应新的data.frame大小:

> df
     x   y
1 a b* d e
3   c*   f

因此,后续索引被中断。

3 个答案:

答案 0 :(得分:4)

这是一个初步解决方案:

# Creating the data frame
df <- data.frame(x = c('a', 'b*', 'c'), y = c('d', 'e', 'f'),stringsAsFactors = FALSE)
df

# Creating a vector of rows with *
ast <- grepl("\\*",df$x)

# For loop
for(i in seq(length(ast),1,-1)){
  if(ast[i]){
    df[i-1,"x"] <- paste(df[i-1,"x"],df[i,"x"],sep=" ")
    df[i-1,"y"] <- paste(df[i-1,"y"],df[i,"y"],sep=" ")
    df <- df[-i,]
  }
}

这是一个初始解决方案,因为您仍需要管理第一行有*以及其他类似情况。我希望这有帮助。

答案 1 :(得分:2)

实际上并没有合并行,但是对于那些具有*的行,它会粘贴前一行的值,然后它会删除在下一行中包含*的行。

library(dplyr)

df <- data.frame(x = c('a', 'b*', 'c'), y = c('d', 'e', 'f'))

df <- mutate(df, 
             Operator = grepl("\\*",x), # Check for *
             lagged.x = lag(x, n = 1),  # Get x value from 1 row ago
             lagged.y = lag(y, n = 1),  # Get y value from 1 row ago
             x = ifelse(Operator, paste(lagged.x, x),x), # if there is * paste lagged x
             y = ifelse(Operator, paste(lagged.y, y),y), # if there is * paste lagged y
             lead.Operator = lead(Operator, n = 1)       # Check if next row has a *
)

# keep only rows that had no * in following row and that had no following row (last row)
df <- filter(df, !lead.Operator | is.na(lead.Operator))

# Select just the x and y columns
df <- select(df, x, y)

答案 2 :(得分:2)

以下是3个替代方案(对于基础R一个,我假设xy是字符而不是因素。我还使您的数据更复杂,以涵盖不同的场景)

(有点复杂的数据集)

df <- data.frame(x = c('p','a', 'b*', 'c*', 'd', 'h*', 'j*', 'l*', 'n'), 
                 y = c('r','d', 'e', 'f', 'g', 'i', 'k', 'm', 'o'), 
                 stringsAsFactors = FALSE)

基础R

aggregate(. ~ ID, 
          transform(df, ID = cumsum(!grepl("*", x, fixed = TRUE))),
          paste, collapse = " ")
#   ID          x       y
# 1  1          p       r
# 2  2    a b* c*   d e f
# 3  3 d h* j* l* g i k m
# 4  4          n       o

data.table

library(data.table)
setDT(df)[, lapply(.SD, paste, collapse = " "), 
            by = .(ID = cumsum(!grepl("*", df[["x"]], fixed = TRUE)))]
#    ID          x       y
# 1:  1          p       r
# 2:  2    a b* c*   d e f
# 3:  3 d h* j* l* g i k m
# 4:  4          n       o

dplyr

library(dplyr)
df %>%
  group_by(ID = cumsum(!grepl("*", x, fixed = TRUE))) %>%
  summarise_all(funs(paste(., collapse = " ")))

# # A tibble: 4 x 3
#      ID          x       y
#   <int>      <chr>   <chr>
# 1     1          p       r
# 2     2    a b* c*   d e f
# 3     3 d h* j* l* g i k m
# 4     4          n       o