如何在R中向上移动每个组中的值

n3h0vuf2  于 2022-12-06  发布在  其他
关注(0)|答案(4)|浏览(111)

我需要将有效值移到每个id内 Dataframe 的顶部。

df <- data.frame(id = c(1,1,1,2,2,2,3,3,3,3),
                 itemid = c(1,2,3,1,2,3,1,2,3,4),
                 values = c(1,NA,0,NA,NA,0,1,NA,0,NA))
    
df
   id itemid values
1   1      1      1
2   1      2     NA
3   1      3      0
4   2      1     NA
5   2      2     NA
6   2      3      0
7   3      1      1
8   3      2     NA
9   3      3      0
10  3      4     NA

不包括id列,当values列中缺少一个值时,我希望将每个id的所有值向顶部对齐。
如何获得下面的所需数据集?

df1
   id itemid values
1   1      1      1
2   1      2      0
3   1      3     NA
4   2      1      0
5   2      2     NA
6   2      3     NA
7   3      1      1
8   3      2      0
9   3      3     NA
10  3      4     NA
2j4z5cfb

2j4z5cfb1#

使用tidyverse,您可以通过values是否缺失来确定arrange(这将把它们放在底部)。

library(tidyverse)

df %>%
  arrange(id, is.na(values))

输出

id itemid values
   <dbl>  <dbl>  <dbl>
 1     1      1      1
 2     1      3      0
 3     1      2     NA
 4     2      3      0
 5     2      1     NA
 6     2      2     NA
 7     3      1      1
 8     3      3      0
 9     3      2     NA
10     3      4     NA

或者,如果希望itemid和其他列保持相同的顺序,可以使用mutate对感兴趣的列进行特定排序(如values)。其他答案提供了很好的解决方案,如@圣地亚哥和@ThomasIsCoding。如果有多个感兴趣的列要将NA移到每组的底部,还可以尝试:

df %>%
  group_by(id) %>%
  mutate(across(.cols = values, ~values[order(is.na(.))]))

其中.cols参数将包含要独立转换和重新排序的列。

输出

id itemid values
   <dbl>  <dbl>  <dbl>
 1     1      1      1
 2     1      2      0
 3     1      3     NA
 4     2      1      0
 5     2      2     NA
 6     2      3     NA
 7     3      1      1
 8     3      2      0
 9     3      3     NA
10     3      4     NA
vwkv1x7d

vwkv1x7d2#

我们可以试试ave + order

> transform(df,  values = ave(values, id, FUN = function(x) x[order(is.na(x))]))
   id itemid values
1   1      1      1
2   1      2      0
3   1      3     NA
4   2      1      0
5   2      2     NA
6   2      3     NA
7   3      1      1
8   3      2      0
9   3      3     NA
10  3      4     NA
cuxqih21

cuxqih213#

使用data.table

library(data.table)

setDT(df)[, values := values[order(is.na(values))], id][]
#>     id itemid values
#>  1:  1      1      1
#>  2:  1      2      0
#>  3:  1      3     NA
#>  4:  2      1      0
#>  5:  2      2     NA
#>  6:  2      3     NA
#>  7:  3      1      1
#>  8:  3      2      0
#>  9:  3      3     NA
#> 10:  3      4     NA
7bsow1i6

7bsow1i64#

我会定义一个函数来完成您想要的任务,然后按id分组:

completed_first <- function(x) {
  completed <- x[!is.na(x)]
  length(completed) <- length(x)
  completed
}

library(dplyr)

df %>%
  group_by(id) %>%
  mutate(
    values = completed_first(values)
  ) %>%
  ungroup()
# # A tibble: 10 × 3
#       id itemid values
#    <dbl>  <dbl>  <dbl>
#  1     1      1      1
#  2     1      2      0
#  3     1      3     NA
#  4     2      1      0
#  5     2      2     NA
#  6     2      3     NA
#  7     3      1      1
#  8     3      2      0
#  9     3      3     NA
# 10     3      4     NA

(This方法会保留itemid的顺序)。
或者基于ThomasIsCoding的答案:

library(dplyr)

df %>%
  group_by(id) %>%
  mutate(
    values = values[order(is.na(values))]
  ) %>%
  ungroup()
# # A tibble: 10 × 3
#       id itemid values
#    <dbl>  <dbl>  <dbl>
#  1     1      1      1
#  2     1      2      0
#  3     1      3     NA
#  4     2      1      0
#  5     2      2     NA
#  6     2      3     NA
#  7     3      1      1
#  8     3      2      0
#  9     3      3     NA
# 10     3      4     NA

相关问题