我在数据框中有一些文本,如下所示
输入
rownumber CStage
1 38-40cm
2 27-22
3 32cm and 40cm
我想在每个CStage
中减去两个数字,输出为
所需的输出
rownumber CStage
1 2
2 5
3 8
我用过stringr::str_extract_all(df$CStage,"\\d{2}")
这给了我一个列表,每个元素包含两个数字
[[1]]
[1] "38" "40"
[[2]]
[1] "27" "22"
[[3]]
[1] "32" "40"
然后我该如何减去两个数字(以获得正输出)
答案 0 :(得分:3)
就像@Cath在评论中提到的那样,您可以使用sapply
,将其转换为数字,并在它们之间采用diff
的含义。
num_list <- stringr::str_extract_all(df$CStage,"\\d{2}")
abs(sapply(num_list, function(x) diff(as.numeric(x))))
#[1] 2 5 8
答案 1 :(得分:1)
您也可以sort
,然后使用diff。
sapply(regmatches(df1$CStage, gregexpr("\\d+", df1$CStage)), function(x)diff(sort(as.numeric(x))))
#[1] 2 5 8
答案 2 :(得分:1)
1)绑可以使用gsubfn中的strapply
紧凑地完成此操作。定义一个正则表达式,以便为CStage
的每个元素提取捕获组中的两个数字,并将它们传递到公式符号中定义的匿名函数中,并返回差的绝对值。
library(gsubfn)
transform(DF, CStage = strapply(CStage,
"(\\d+)\\D+(\\d+)",
~ abs(as.numeric(x) - as.numeric(y)),
simplify = TRUE))
给予:
rownumber CStage
1 1 2
2 2 5
3 3 8
2)基本R 通过用CStage
中的空格替换非数字,并使用read.table
读取它们以创建数据框,可以获得基本R解决方案具有V1和V2列。减去这些列并取绝对值。
transform(DF, CStage = with(read.table(text = gsub("\\D", " ", CStage)), abs(V1-V2)))
给予:
rownumber CStage
1 1 2
2 2 5
3 3 8
3)dplyr / tidyr 一种使用dplyr和tidyr的解决方案,其方法与(2)类似:
library(dplyr)
library(tidyr)
DF %>%
separate(CStage, into = c("V1", "V2"), sep = "\\D+",
extra = "drop", convert = TRUE) %>%
mutate(CStage = abs(V1 - V2)) %>%
select(rownumber, CStage)
给予:
rownumber CStage
1 1 2
2 2 5
3 3 8
可重复输入的形式是:
Lines <- "
rownumber,CStage
1,38-40cm
2,27-22
3,32cm and 40cm"
DF <- read.csv(text = Lines, as.is = TRUE)