【问题标题】:Using R to extract data from a dataframe and store data in unknown number of new columns使用 R 从数据框中提取数据并将数据存储在未知数量的新列中
【发布时间】:2020-10-17 20:58:03
【问题描述】:

我有一个如下的数据框:

library(dplyr)
df <- data.frame(A=1:20, 
                  B=c(2,1.8,1.6,1.8,4,6,8,10,12,10,8,6,13,14,15,16,16.5,15,14,13))
mutate(df, C = B - lag(B))
A   B     C
1   2.0   NA
2   1.8 -0.2
3   1.6 -0.2
4   1.8  0.2
5   4.0  2.2
6   6.0  2.0
7   8.0  2.0
8   10.0  2.0
9   12.0  2.0
10  10.0 -2.0
11  8.0 -2.0
12  6.0 -2.0
13  13.0  7.0
14  14.0  1.0
15  15.0  1.0
16  16.0  1.0
17  16.5 -0.5
18  15.0 -1.0
19  14.0 -1.0
20  13.0 -1.0

我想提取出连续有 3 个或更多的负值序列并放在单独的列中。例如,将 (col C) 第 10、11、12 行的值放在新列中,将第 17、18、19、20 行的值放在另一个新列中。这个数据框很大,所以我不知道我会有多少新列。任何帮助,将不胜感激。谢谢

【问题讨论】:

  • 你想只为C列还是每列都这样做?
  • 是的,只有 C 列
  • @akrun - 你的意思是连续超过 3 个值吗?如果是这样,那将是一个新的数据列
  • 抱歉,B col 应该是 16.5 - 我现在已经在那里更新了。非常感谢

标签: r dataframe dplyr data-extraction


【解决方案1】:

这是一个带有rleid 的选项,用于根据“C”列的sign 创建一个运行长度-id 分组,即具有相同sign 的那些相邻元素将具有相同的分组“id”并且它当sign 有差异时会增加。然后,我们根据计数 (n()) 值将列创建为特定数字,即 3 或 4

library(dplyr)
library(data.table)
df %>%
   mutate(C = B - lag(B)) %>%
  group_by(grp = rleid(sign(C))) %>%
  mutate(newC3 = if(n() ==3 && all(C < 0)) C else NA,
         newC4 = if(n() == 4 && all(C < 0) C else NA)

为了实现自动化,pivot_wider 可以在使用rleid 创建分组 id 并将非负值替换为NA 后从“长”格式重新调整为“宽”格式。这样,我们只得到负值块在单独的列中

library(tidyr)
library(stringr)
df %>%
   mutate(C = B - lag(B)) %>%
   mutate(grp = str_c('C', rleid(sign(C))), 
     C1 = case_when(C >=0 ~ NA_real_, TRUE ~ C)) %>%
   pivot_wider(names_from = grp, values_from = C1)%>%
   select(where(~ sum(!is.na(.)) > 0))

-输出

# A tibble: 20 x 6
#       A     B      C     C2    C4    C7
#   <int> <dbl>  <dbl>  <dbl> <dbl> <dbl>
# 1     1   2   NA     NA        NA    NA
# 2     2   1.8 -0.200 -0.200    NA    NA
# 3     3   1.6 -0.200 -0.200    NA    NA
# 4     4   1.8  0.200 NA        NA    NA
# 5     5   4    2.2   NA        NA    NA
# 6     6   6    2     NA        NA    NA
# 7     7   8    2     NA        NA    NA
# 8     8  10    2     NA        NA    NA
# 9     9  12    2     NA        NA    NA
#10    10  10   -2     NA        -2    NA
#11    11   8   -2     NA        -2    NA
#12    12   6   -2     NA        -2    NA
#13    13  13    7     NA        NA    NA
#14    14  14    1     NA        NA    NA
#15    15  15    1     NA        NA    NA
#16    16  16    1     NA        NA    NA
#17    17  16    0     NA        NA    NA
#18    18  15   -1     NA        NA    -1
#19    19  14   -1     NA        NA    -1
#20    20  13   -1     NA        NA    -1

注意:列名称“C2”、“C4”、“C7”基于使用 rleid 创建的 ID。如果我们想重命名,那么可以使用rename_withrename_at来完成

...
  %>%
   rename_at(vars(matches('^C\\d+')), ~ str_c('C', seq_along(.)))

【讨论】:

  • 您介意解释一下自动化版本吗 - 非常强大。谢谢
  • 绝对精彩。再次感谢
  • 顺便说一句,假设它是连续 5 行 - 我如何将其更改为 5(而不是目前的 3)谢谢
  • @user1655130 在第一个选项中,它只是为了利用if(n() ==5 &amp;&amp; all(C &lt; 0)) C else NA,在第二种情况下,你想要group_by(grp) %&gt;% mutate(C1 = case_when(C &lt; 0 &amp; n() ==5 ~ C))
猜你喜欢
  • 2022-01-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-06-12
  • 2021-11-27
  • 1970-01-01
  • 2021-06-12
  • 1970-01-01
相关资源
最近更新 更多