>我在 R 中有一个数据帧,我从一个文本文件中读入它,该文件包含两列,每列每个值有多个整数。我需要从一列(开始(中减去另一列(结束(中的相应整数的相应整数。最后一步,我最终想要得到的是将所有距离相加,以获得每条轨道的总距离。下面的数据帧只是一个示例,但有问题的数据帧每列大约有 20 个整数,并且有几十个轨道(行(。
轨道 A: (15-6(+(20-5(+(7-1(
track StartDist EndDist
A 1, 5, 6 7, 20, 15
B 1, 7, 8, 11 6, 21, 22, 25
我会使用 separate()
函数,但每列的整数数量不相等。我还考虑过重新制作数据帧,每行只包含一个整数,但我最终会得到成千上万行,然后必须再次将它们组合回来以计算每个轨道的总数。有什么建议吗?
下面是一个基本的 R 解决方案。我们使用split
按track
对条目进行分组,然后使用自定义函数splt
将条目拆分为列StartDist
,并按", "
EndDist
;然后我们使用 mapply
计算成对差异,并返回第 sum.diff
列中所有成对距离的总和。
splt <- function(x) as.numeric(unlist(strsplit(as.character(x), ", ")))
df$sum.diff = sapply(split(df, df$track), function(x) {
start <- splt(x$StartDist);
end <- splt(x$EndDist);
sum(mapply(function(a, b) b - a, start, end)) });
df;
# track StartDist EndDist sum.diff
#1 A 1, 5, 6 7, 20, 15 30
#2 B 1, 7, 8, 11 6, 21, 22, 25 47
示例数据
df <- read.table(text =
"track StartDist EndDist
A '1, 5, 6' '7, 20, 15'
B '1, 7, 8, 11' '6, 21, 22, 25'", header = T)
我真的建议将其存储为"长"文件,以使任何后续分析变得更加简单。如果你在整洁的世界里,我会做这样的事情:
library(tidyverse)
datlong <- dat %>%
mutate_at(vars(StartDist, EndDist), str_split, ",\s+") %>%
unnest %>%
mutate_at(vars(StartDist, EndDist), as.numeric)
datlong %>%
group_by(track) %>%
summarise(Len = sum(EndDist - StartDist))
# A tibble: 2 x 2
# track Len
# <chr> <dbl>
#1 A 30
#2 B 47
dat
在哪里:
txt <- "track|StartDist|EndDist
A|1, 5, 6|7, 20, 15
B|1, 7, 8, 11|6, 21, 22, 25"
dat <- read.table(text=txt, sep="|", header=TRUE, stringsAsFactors=FALSE)
以及用于娱乐和游戏的基本 R 翻译:
vars <- c("StartDist", "EndDist")
othvars <- setdiff(names(dat), vars)
dat[vars] <- lapply(dat[vars], strsplit, ",\s+")
datlong <- cbind(
dat[othvars][rep(seq_len(nrow(dat)), lengths(dat[[vars[1]]])),, drop=FALSE],
lapply(dat[vars], unlist),
stringsAsFactors=FALSE
)
datlong[vars] <- lapply(datlong[vars], as.numeric)
aggregate(cbind(Len = EndDist - StartDist) ~ track, data=datlong, FUN=sum)
这是一个dplyr
解决方案,它也使用 stringr
.我们使用 rowwise()
和 mutate
对每一行应用以下操作: str_split()
将每个"Dist"列中的字符串分隔为字母数字字符串列表,然后取消列出,强制转换为数字向量,并按您请求的顺序减去。然后将生成的数值向量的元素相加。
就其价值而言,我更喜欢基本R解决方案,因此我认为Maurits Evers的解决方案更优雅:
library(dplyr)
library(stringr)
track <- c("A", "B")
StartDist <- c("1, 5, 6", "1, 7, 8, 11")
EndDist <- c("7, 20, 15", "6, 21, 22, 25")
df <- data.frame(track,StartDist,EndDist)
df <- mutate(rowwise(df),
sum = sum(as.numeric(unlist(str_split(EndDist, ","))) - as.numeric(unlist(str_split(StartDist, ",")))))
输出:
# A tibble: 2 x 4
track StartDist EndDist sum
<fct> <fct> <fct> <dbl>
1 A 1, 5, 6 7, 20, 15 30.
2 B 1, 7, 8, 11 6, 21, 22, 25 47.