R 拆分字符串并将其添加为新行

R 拆分字符串并将其添加为新行,r,R,我有以下数据集: df<-data.frame (fact= c("a,b,c,d","f,g,h,v"), value = c("0,1,0,1" , "0,0,1,0")) 我希望在值为1时拆分它。因此,我的理想输出是: fact value 1: a,b 0,1 2: c,d 0,1 3: f,g,h 0,0,1 4: v 0 首先,我想我可以通过使用cut找到一种方法,比如: cut(as.numeric(strsplit(a

我有以下数据集:

df<-data.frame (fact= c("a,b,c,d","f,g,h,v"), value = c("0,1,0,1" , "0,0,1,0"))
我希望在值为1时拆分它。因此,我的理想输出是:

 fact     value

1:  a,b     0,1
2:  c,d     0,1
3: f,g,h    0,0,1
4:  v       0
首先,我想我可以通过使用
cut
找到一种方法,比如:

cut(as.numeric(strsplit(as.character(df$value), split = ",")), breaks =1)

但我的尝试都没有成功

一种方法是将原始数据帧中
事实
的字符向量拆分为
,“
使用
strsplit
,然后确定第一个
“1”
在拆分的
中的位置。然后使用此位置确定
事实
的拆分:

sv <- strsplit(df$value,",")
sf <- strsplit(df$fact,",")
pos <- sapply(sv, function(sv) {j <- which(sv=="1"); if (length(j)==0) NA else j[1]})
out <- do.call(rbind,lapply(1:length(pos),function(i,sv,sf,pos) {
  if (is.na(pos[i]) || pos[i] == length(sf[[i]])) 
    data.frame(fact=toString(sf[[i]]),value=toString(sv[[i]])) 
  else 
    data.frame(fact=c(toString(sf[[i]][1:pos[i]]),
                      toString(sf[[i]][(pos[i]+1):length(sf[[i]])])),
               value=c(toString(sv[[i]][1:pos[i]]),
                       toString(sv[[i]][(pos[i]+1):length(sv[[i]])])))
  },sv,sf,pos))
##     fact   value
##1    a, b    0, 1
##2    c, d    0, 1
##3 f, g, h 0, 0, 1
##4       v       0

sv首先,我们将
fact
value
中的字符串拆分为单独的值,并将它们堆叠起来,使每个值成为数据帧中的一列值。现在,使用
value
,我们希望每一次运行的0后面跟一个1成为一个组。这些是我们希望在最后粘贴在一起的值组。我们将使用
dplyr
对每组分别进行操作,以返回最终数据帧

library(dplyr) 
library(purrr)  # For map function
library(tidyr)  # For separate_rows function

df %>% 
  separate_rows(fact, value, sep=",") %>%
  mutate(group = lag(cumsum(value == 1), default=0)) %>%
  group_by(group) %>%
  summarise(fact = paste(fact, collapse=","),
            value = paste(value, collapse=",")) %>%
  select(-group)     

   fact value 
1   a,b   0,1
2   c,d   0,1
3 f,g,h 0,0,1
4     v     0

另一个基本R尝试:

sf <- strsplit(as.character(df$fact), ",")
sv <- strsplit(as.character(df$value), ",")
spl <- lapply(sv, function(x) -rev(cumsum(as.numeric(rev(x)))) )
#[[1]]
#[1] -2 -2 -1 -1
#
#[[2]]
#[1] -1 -1 -1  0

joinfun <- function(x) sapply(unlist(Map(split, x, spl), rec=FALSE), paste, collapse=",")

# to show you what is happening:
#> Map(split, sf, spl)
#[[1]]
#[[1]]$`-2`
#[1] "a" "b"
#
#[[1]]$`-1`
#[1] "c" "d"
# 
#
#[[2]]
#[[2]]$`-1`
#[1] "f" "g" "h"
#
#[[2]]$`0`
#[1] "v"

data.frame(fact  = joinfun(sf), value = joinfun(sv) )
#   fact value
#1   a,b   0,1
#2   c,d   0,1
#3 f,g,h 0,0,1
#4     v     0

sf一种数据表方法如下。使用
splitstackshape
包中的
cSplit()
拆分
fact
value
中的每个元素。这将以长格式创建data.table。得到结果后,使用
diff()
cumsum()
创建一个组变量,只要
值的差值小于0,R就会创建一个新组。然后,您希望将
paste()
应用于
fact
value
。您可以使用
lappy(.SD…
实现这一点。这相当于
dplyr
包中的
summary_at()
。最后,删除组变量

library(splitstackshape)
library(data.table)

cSplit(df, splitCols = c("fact", "value"),
       direction = "long", sep = ",") -> temp

temp[, group := cumsum(c(FALSE, diff(value) < 0))][,
       lapply(.SD, function(x){paste(x, collapse = ",")}),
       .SDcols = fact:value,
       by = group][, group :=NULL] -> out

#    fact value
#1:   a,b   0,1
#2:   c,d   0,1
#3: f,g,h 0,0,1
#4:     v     0
库(splitstackshape)
库(数据表)
cSplit(df,splitCols=c(“事实”,“值”),
direction=“long”,sep=“,”->temp
温度[,组:=cumsum(c(假,差(值)<0))],
lappy(.SD,函数(x){paste(x,collapse=“,”)}),
.SDcols=事实:值,
by=group][,group:=NULL]->out
#事实价值
#1:a,b0,1
#2:c,d0,1
#3:f,g,h0,0,1
#4:V0

派对有点晚了,但这里有一个利用
正则表达式和
tidyverse
函数的解决方案:

#install.packages("devtools")
#devtools::install_github("hadley/tidyverse")

library(tidyverse)

dff <- data.frame(fact= c("a,b,c,d","f,g,h,v"), 
                   value = c("0,1,0,1" , "0,0,1,0"), 
                   stringsAsFactors = F)

dff %>% 
  mutate(value = gsub("(?<=1),(?=0)","-", value, perl = T)) %>%
  group_by(value) %>%
  mutate(indices = which(strsplit(value,split="")[[1]]=="-"),
         fact = sprintf("%s-%s", 
                        substr(fact, 0, indices - 1), 
                        substr(fact, indices + 1, nchar(fact)))) %>%
  select(fact, value) %>% 
  ungroup() %>%
  separate_rows(fact, value, sep = "-")

我们已经用这个更简单的解决方案代替了这个解决方案

没有使用任何软件包。
df
的列可以是字符或因子——代码将它们转换为字符<代码>值
输入中的条目可能不包含任何值。输入的同一行上的
事实
组件应具有相同数量的逗号分隔字段,但不同行上的字段数量可能不同

do.call("rbind", by(df, 1:nrow(df), function(x) {
  long <- lapply(x, function(x) unlist(strsplit(as.character(x), ",")))
  g <- -rev(cumsum(rev(long$value == 1)))
  aggregate(long, list(g), paste, collapse = ",")[names(x)]
}))
by
调用每行显示一次的匿名函数。对于每一行,它用逗号分隔每一列,给出该行的长格式
long
。例如,对于处理
df
第一行的迭代,
long
的值为:

long <- list(fact = c("a", "b", "c", "d"), value = c("0", "1", "0", "1"))
最后,我们通过
g
将具有相同组的每个列中的元素粘贴在一起来聚合。我们删除了
agggeate
添加的额外列


最后,我们将所有行的data.frames放在一起。

单独的行很整洁-实际上,我们不知道这一点非常方便。
do.call("rbind", by(df, 1:nrow(df), function(x) {
  long <- lapply(x, function(x) unlist(strsplit(as.character(x), ",")))
  g <- -rev(cumsum(rev(long$value == 1)))
  aggregate(long, list(g), paste, collapse = ",")[names(x)]
}))
   fact value
1   a,b   0,1
2   c,d   0,1
5 f,g,h 0,0,1
6     v     0
long <- list(fact = c("a", "b", "c", "d"), value = c("0", "1", "0", "1"))
g <- c(-2L, -2L, -1L, -1L)