R字符串中的总和

时间:2019-02-05 12:32:01

标签: r string sum

我有一个问题:

我有一个像这样简单的例子的数据集:

df<-data.frame(ID=c("A","B","C","D"),
               Score=c("15","16/18/19+2/6","3/+2","19/18/14"))

我想最后得到一个已拆​​分score数字的数据集。我对/+2部分有疑问。当它说"3/+2"时,实际上是指:"3/3+2",最终将得到"3/5"。因此,我需要帮助的是最终得到一个像这样的数据集:

  ID         Score
  A            15
  B 16/18/19/21/6
  C           3/5
  D      19/18/14

我已经发现我可以将分数分开

df<-df %>% 
  mutate(Score = strsplit(as.character(ID), "/")) %>%
  unnest(Score)

但是我不知道如何让数字重复,然后在/ +出现时求和,有人可以帮我吗?

3 个答案:

答案 0 :(得分:3)

可能可以用更优雅的方式解决它,但这是一种可能性:

df %>%
 mutate(Score = strsplit(as.character(Score), "/")) %>%
 unnest() %>%
 rowwise() %>%
 mutate(Score = eval(parse(text = paste0(Score)))) %>%
 group_by(ID) %>%
 mutate(Score = paste0(Score, collapse = "/")) %>%
 distinct()

  ID    Score     
  <fct> <chr>     
1 A     15        
2 B     16/18/21/6
3 C     3/5       
4 D     19/18/14  

样本数据:

df <- data.frame(ID=c("A","B","C","D"),
               Score=c("15","16/18/19+2/6","3/3+2","19/18/14"))

它基于/拆分“分数”,然后通过parse()将字符转换为表达式,然后将其转换回。

使用您提供的数据和@A中的模式。苏里曼:

df %>%
 mutate(Score = strsplit(gsub("(\\d+)/*\\+(\\d+)","\\1/\\1+\\2", Score), "/")) %>%
 unnest() %>%
 rowwise() %>%
 mutate(Score = eval(parse(text = paste0(Score)))) %>%
 group_by(ID) %>%
 mutate(Score = paste0(Score, collapse = "/")) %>%
 distinct()

  ID    Score        
  <fct> <chr>        
1 A     15           
2 B     16/18/19/21/6
3 C     3/5          
4 D     19/18/14 

答案 1 :(得分:1)

library(dplyr)
library(tidyr) #separate_rows, no need for unnest
df %>% rowwise()%>% 
       mutate(Score_upd=paste0(sapply(unlist(strsplit(gsub('(\\d+)/*\\+(\\d+)','\\1/\\1+\\2',Score),'/')),
       function(x)eval(parse(text = x))),collapse = '/')) %>% 
       separate_rows(Score_upd,sep = '/')

#short version
df %>% mutate(Score=gsub('(\\d+)/*\\+(\\d+)','\\1/\\1+\\2',Score)) %>% 
       separate_rows(Score,sep='/') %>% rowwise() %>% mutate(Score=eval(parse(text=Score))) %>% 
       group_by(ID) %>% summarise(Score=paste0(Score,collapse = '/'))

# A tibble: 4 x 2
  ID    Score        
  <fct> <chr>        
  1 A     15           
  2 B     16/18/19/21/6
  3 C     3/5          
  4 D     19/18/14

主要思想是使用gsub正确分隔2+3,例如:

gsub('(\\d+)/*\\+(\\d+)','\\1/\\1+\\2','20/8/2+3') #/* means 0 or 1 occurence of / e.g, 19+2 and 3/+2.
[1] "20/8/2/2+3"

然后

valid_str <- gsub('(\\d+)/*\\+(\\d+)','\\1/\\1+\\2','20/8/2+3')
sapply(unlist(strsplit(valid_str,'/')),function(x) eval(parse(text=x)))
20   8   2 2+3 
20   8   2   5 
#OR
sapply(unlist(strsplit(valid_str,'/')),function(x) sum(as.numeric(unlist(strsplit(x,'\\+')))))
20   8   2 2+3 
20   8   2   5

答案 2 :(得分:1)

我们可以使用gsubfn以紧凑的方式完成

library(gsubfn)
library(tidyverse)
df %>% 
   mutate(Score = gsubfn("\\d+\\+\\d+", ~ eval(parse(text = x)), Score))
# ID      Score
#1  A         15
#2  B 16/18/21/6
#3  C        3/5
#4  D   19/18/14

数据

df <- data.frame(ID=c("A","B","C","D"),
           Score=c("15","16/18/19+2/6","3/3+2","19/18/14"), stringsAsFactors = FALSE)