【问题标题】:Separating large dataframe in R with multiple integers in each column, then summing integers将 R 中的大数据框与每列中的多个整数分开,然后对整数求和
【发布时间】:2018-04-13 09:23:05
【问题描述】:

我在 R 中有一个数据框,我从一个包含两列的文本文件中读取,每列的每个值都有多个整数。我需要从另一列(End)中的相应整数中减去一列(Start)中的相应整数。最后一步我最终想要得到的是将所有距离相加,以获得每条轨道的总距离。下面的数据框只是一个示例,但有问题的数据框每列大约有 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(),但每列的整数数量不相等。我还考虑过重新制作数据框,每行只包含一个整数,但我最终会得到成千上万行,然后必须再次将它们组合回来以计算每个轨道的总数。有什么建议吗?

【问题讨论】:

  • 制作你的“长”文件,每行只包含一个整数是我通常会做的。然后,您可以简单地执行 End-Start 并使用任意数量的函数(如 base R 中的 aggregate、dplyr 的 group_by 或 data.table 的 by= 处理)计算每个 track 组的总和。
  • @thelatemail 如果您可以将其扩展为正确的答案,将会很高兴。这是一个很好的问题 imo,答案会很棒!

标签: r dataframe


【解决方案1】:

这是一个基本的 R 解决方案。我们使用splittrack对条目进行分组,然后使用自定义函数spltStartDistEndDist中的条目拆分为", ";然后我们使用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)

【讨论】:

    【解决方案2】:

    我真的建议将其存储为“长”文件,以使任何后续分析变得更加简单。如果你在 tidyverse 世界,我会做这样的事情:

    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)
    

    【讨论】:

      【解决方案3】:

      这是一个dplyr 解决方案,它也使用stringr。我们使用rowwise()mutate每个 行应用以下操作:str_split() 将每个“Dist”列中的字符串分隔成一个字母数字字符串列表,然后不列出,强制执行到数字向量,并按您要求的顺序减去。然后将结果数值向量的元素相加。

      就其价值而言,我更喜欢 base 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.
      

      【讨论】:

        猜你喜欢
        • 2020-04-25
        • 2021-12-13
        • 2019-03-25
        • 2020-06-22
        • 2016-03-21
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-04-30
        相关资源
        最近更新 更多