【问题标题】:counting leading & trailing zeros for every row in a dataframe in R计算R中数据框中每一行的前导零和尾随零
【发布时间】:2021-10-31 03:20:45
【问题描述】:

我正在尝试分析每行代表一个时间序列的数据框。我的 df 结构如下:

df <- data.frame(key = c("10A", "11xy", "445pe"), 
                 Obs1 = c(0, 22, 0),
                 Obs2 = c(10, 0, 0),
                 Obs3 = c(0,  3, 5),
                 Obs4 = c(0, 10, 0)
)

我现在想创建一个新的数据框,其中每一行再次代表键,列包含以下结果:

  1. “TotalZeros”:计算每行的零总数 (=key)
  2. “LeadingZeros”:计算每行第一个非零 obs 之前的零数

这意味着我希望最终收到以下数据帧:

key   TotalZeros   LeadingZeros
10A            3              1
11xy           1              0
445pe          3              2

我设法计算了每一行的零总数:

zeroCountDf <- data.frame(key = df$key, TotalNonZeros = rowSums(df ! = 0))

但我正在努力计算LeadingZeros。我找到了如何计算向量中的第一个非零位置,但我不明白如何将这种方法应用于我的数据框:

vec <- c(0,1,1)
min(which(vec != 0)) # returns 2, meaning the second position is first nonzero value

谁能解释如何计算数据框中每一行的前导零?我是 R 新手,感谢任何见解和提示。提前致谢。

【问题讨论】:

    标签: r dataframe zero


    【解决方案1】:

    data.table 选项

    setDT(df)[
      , .(
        total_zeros = rowSums(.SD == 0),
        Leading_zeros = which.max(.SD != 0) - 1,
        Trailing_zeros = length(.SD)-max(which(.SD!=0)) 
      ),
      key
    ]
    

    给予

         key total_zeros Leading_zeros Trailing_zeros
    1:   10A           3             1              2
    2:  11xy           1             0              0
    3: 445pe           3             2              1
    

    【讨论】:

      【解决方案2】:

      我们可以使用来自matrixStatsrowCumsumsrowSums

      library(matrixStats)
      cbind(df[1], total_zeros = rowSums(df[-1] == 0), 
           Leading_zeros = rowSums(!rowCumsums(df[-1] != 0)))
      

      -输出

           key total_zeros Leading_zeros
      1   10A           3              1
      2  11xy           1              0
      3 445pe           3              2
      

      或者在tidyverse中,我们也可以使用rowwise

      library(dplyr)
      df %>% 
         mutate(total_zeros = rowSums(select(., starts_with("Obs")) == 0)) %>%
         rowwise %>%
         transmute(key, total_zeros,
             Leading_zeros = sum(!cumsum(c_across(starts_with('Obs')) != 0))) %>%
            ungroup
      

      -输出

      # A tibble: 3 x 3
        key   total_zeros Leading_zeros
        <chr>       <dbl>         <int>
      1 10A             3             1
      2 11xy            1             0
      3 445pe           3             2
      

      【讨论】:

      • rowcumsum 不错!
      【解决方案3】:

      编辑在解决方案中添加了 Miff 的评论。

      这是tidyverse 解决方案:

      library(dplyr)
      library(tidyr)
      
      df %>% 
        pivot_longer(starts_with("Obs"),
                     names_pattern = "Obs(\\d+)") %>% 
        arrange(key, as.integer(name)) %>% 
        group_by(key) %>% 
        summarize(
          leading_zeros = sum(cumsum(abs(value)) == 0),
          total_zeros   = sum(value == 0),
          trailing_zeros = sum(cumsum(abs(value)) == last(cumsum(abs(value)))) - 1)
      

      返回

      # A tibble: 3 x 4
        key   leading_zeros total_zeros trailing_zeros
        <chr>         <int>       <int>          <dbl>
      1 10A               1           3              2
      2 11xy              0           1              0
      3 445pe             2           3              1
      

      【讨论】:

      • 可能不太可能,但如果您同时有正数和负数,sum(cumsum(value) == 0) 可能会多计,因此sum(cumsum(abs(value)) == 0) 会更稳健
      • 你是对的。我在解决方案中添加了abs
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-10-14
      • 2014-08-09
      • 1970-01-01
      • 2020-11-22
      相关资源
      最近更新 更多