提问人:Alinnaeus 提问时间:7/13/2022 最后编辑:Alinnaeus 更新时间:7/13/2022 访问量:56
R 中的数据操作:如果我> i-1,则开始新行
Data manipulation in R: Starting a new row if i > i-1
问:
我有一个很长(一行)数据文件,其中包含许多值。它需要分解为多行。虽然我为什么需要这样做的细节并不重要,但逻辑是列 i 应该始终大于列 i+1。即,沿一行的值应该递减。
我能想到的最好的方法是使用“if then”风格的函数将数据框分解为多行:如果列 i > i-1,则开始新行。如果我< i-1,请将此值保留在行中。
#Example data but with similar format to my real data
df <- data.frame(matrix(ncol = 9, nrow = 1))
df[1,] <- c(3, 2, 1, 2, 1, 1, 3, 2, 1)
我希望它最终看起来像这样。
3 2 1
2 1
1
3 2 1
我不是很精通引用 i 在数据帧中的位置的函数以及这需要的数据操作类型。任何建议将不胜感激。
答:
1赞
dcsuka
7/13/2022
#1
这是一个整洁的解决方案。如果这解决了您的问题,请告诉我:
library(tidyverse)
df <- data.frame(matrix(ncol = 9, nrow = 1))
df[1,] <- c(3, 2, 1, 2, 1, 1, 3, 2, 1)
df %>%
pivot_longer(cols = everything(), names_to = "vars") %>%
mutate(smaller_than_prev = value < lag(value) | is.na(lag(value)),
num_falses = cumsum(smaller_than_prev == FALSE)) %>%
group_by(num_falses) %>%
mutate(row_num = row_number()) %>%
pivot_wider(names_from = row_num, values_from = value, values_fill = NA, names_prefix = "var") %>%
fill(c(`var1`, `var2`, `var3`), .direction = "downup") %>%
slice_head(n = 1) %>%
ungroup() %>%
select(`var1`, `var2`, `var3`)
评论
0赞
Alinnaeus
7/13/2022
谢谢!这正是我想要它做的事情。而且它很容易编辑,可以有更多列(我的真实数据集最多有 20 列)。
0赞
Alinnaeus
7/13/2022
啊,当我将它与我的真实数据一起使用时,我意识到并非所有行都在减少。在某些情况下,也有一些小幅增加。但这是一个简单的解决方案。我刚刚调整了 lag(value) 以适应这种细微的变化,其中: mutate(smaller_than_prev = value <= lag(value*1.05)
0赞
dcsuka
7/13/2022
很高兴听到解决方案得到解决!
2赞
dcarlson
7/13/2022
#2
将向量拆分为组很简单,但最终如何存储数据取决于您尝试对结果执行的操作。以下是拆分数据的简单方法:
vect <- unname(unlist(df)) # Convert the data to a simple vector
cut <- which(diff(vect) >= 0) # Find the points for splitting the vector
grps <- rep(1:4, diff(c(0, cut, length(vect)))) # Define the groups created
groups <- split(vect, grps) # Create a list containing the groups
groups
# $`1`
# [1] 3 2 1
#
# $`2`
# [1] 2 1
#
# $`3`
# [1] 1
#
# $`4`
# [1] 3 2 1
数据框和矩阵要求所有列的长度相同,因此这些列不是可用于保存结果的结构。要转换为矩阵,我们需要填充缺失值:
maxno <- max(sapply(groups, length)) # How long is the longest run?
t(sapply(groups, function(x) c(x, rep(NA, maxno - length(x)))))
# [,1] [,2] [,3]
# 1 3 2 1
# 2 2 1 NA
# 3 1 NA NA
# 4 3 2 1
1赞
jay.sf
7/13/2022
#3
我们可以 erences 和 where 非否定,即 i > i - 1。 cumsum
diff
split
x <- df[1, ] |> unname()
r <- split(x, cumsum(c(1, diff(x)) >= 0))
r
# $`1`
# X1 X2 X3
# 3 2 1
#
# $`2`
# X4 X5
# 2 1
#
# $`3`
# X6
# 1
#
# $`4`
# X7 X8 X9
# 3 2 1
为了创建数据帧,我们协调了 s 和 .length
rbind
do.call(rbind, lapply(r, `length<-`, max(lengths(r))))
# X1 X2 X3
# 1 3 2 1
# 2 2 1 NA
# 3 1 NA NA
# 4 3 2 1
这也适用于开箱即用的“小增加”i > i - 1 ± tol.,OP 谈到,
set.seed(424643)
(x2 <- x + rnorm(length(x), 0, .02))
# X1 X2 X3 X4 X5 X6 X7 X8 X9
# 2.9989375 1.9675093 0.9695195 2.0286091 0.9860200 0.9867120 3.0126058 2.0082577 1.0027076
split(x2, cumsum(c(1, diff(x2)) >= 0))
# $`1`
# X1 X2 X3
# 2.9989375 1.9675093 0.9695195
#
# $`2`
# X4 X5
# 2.028609 0.986020
#
# $`3`
# X6
# 0.986712
#
# $`4`
# X7 X8 X9
# 3.012606 2.008258 1.002708
对于小的减少,在这种情况下,我们可以将零比较调整为一个小的公差值。-.02
set.seed(219291)
(x2 <- x + rnorm(length(x), 0, .02))
# X1 X2 X3 X4 X5 X6 X7 X8 X9
# 2.9866361 2.0236431 1.0053049 2.0061573 1.0348428 1.0008761 3.0145685 2.0016665 0.9719804
split(x2, cumsum(c(1, diff(x2)) >= 0 + -.02))
# $`1`
# X1 X2 X3
# 3.0109922 2.0061321 0.9900378
#
# $`2`
# X4 X5
# 1.9728080 0.9973932
#
# $`3`
# X6
# 0.9829894
#
# $`4`
# X7 X8 X9
# 3.003697 1.997184 0.984649
数据:
df <- structure(list(X1 = 3, X2 = 2, X3 = 1, X4 = 2, X5 = 1, X6 = 1,
X7 = 3, X8 = 2, X9 = 1), row.names = c(NA, -1L), class = "data.frame")
评论