R 将前3个值保持在一行中,将其他所有值更改为NA

R 将前3个值保持在一行中,将其他所有值更改为NA,r,dplyr,tidyverse,R,Dplyr,Tidyverse,使用mtcars实现再现性 (这是一个行操作)。我想根据它们的大小将3个值保持在一行中(因此,基本上前3个值将具有值,其余所有值都更改为NA) 我尝试使用pivot_将数据转换为长数据,然后进行过滤,但问题是我想再次转换为宽数据,因为我想保留数据的结构 mtcars %>% pivot_longer(cols = everything()) %>% group_by(name) %>% top_n(3) 3排mtcars上的样本输出 注意:在mtc

使用mtcars实现再现性

(这是一个行操作)。我想根据它们的大小将3个值保持在一行中(因此,基本上前3个值将具有值,其余所有值都更改为NA)

我尝试使用pivot_将数据转换为长数据,然后进行过滤,但问题是我想再次转换为宽数据,因为我想保留数据的结构

   mtcars %>% 
    pivot_longer(cols = everything()) %>% 
    group_by(name) %>% top_n(3) 
3排mtcars上的样本输出


注意:在mtcars中,所有3行的列名值都与非NA相同,但在原始数据集中则不同。(最好是tidyverse溶液)

我知道您想要tidyverse溶液,但这是R底的一层:

t(应用(mtcars,1,功能(x){x[顺序(x)[1:(长度(x)-3)]mpg气缸显示高压拖动重量qsec vs调幅齿轮carb
#>马自达RX4 21.0北美160.0 110北美
#>马自达RX4 Wag 21.0北美160.0 110北美
#>Datsun 710 22.8 NA 108.0 93 NA NA NA
#>大黄蜂4路21.4北美258.0 110北美北美北美北美
#>大黄蜂运动约18.7 NA 360.0 175 NA NA NA
#>Valiant NA 225.0 105 NA 20.22 NA
#>除尘器360 NA 360.0 245 NA 15.84 NA NA
#>Merc 240D 24.4不适用146.7 62不适用
#>Merc 230 NA 140.8 95 NA 22.90 NA NA
#>Merc 280 19.2 NA 167.6 123 NA NA
#>Merc 280C NA 167.6 123 NA 18.90 NA NA
#>Merc 450SE NA 275.8 180 NA 17.40 NA
#>美世450SL NA 275.8 180 NA 17.60 NA
#>Merc 450SLC NA 275.8 180 NA 18.00 NA NA
#>卡迪拉克弗利特伍德NA 472.0 205 NA 17.98 NA NA NA
#>林肯大陆北美460.0 215北美17.82北美
#>克莱斯勒帝国NA 440.0 230 NA 17.42 NA NA
#>菲亚特128 32.4北美78.7 66北美
#>本田思域30.4 NA 75.7 52 NA NA NA
#>丰田花冠33.9 NA 71.1 65 NA NA
#>丰田科罗纳21.5 NA 120.1 97 NA NA NA
#>道奇挑战者NA 318.0 150 NA 16.87 NA NA
#>AMC标枪NA 304.0 150 NA 17.30 NA NA
#>Camaro Z28 NA 350.0 245 NA 15.41 NA NA
#>庞蒂亚克火鸟19.2 NA 400.0 175 NA NA NA
#>菲亚特X1-9 27.3 NA 79.0 66 NA
#>保时捷914-2 26.0 NA 120.3 91 NA NA NA NA NA
#>莲花欧罗巴30.4 NA 95.1 113 NA
#>福特Pantera L 15.8北美351.0 264北美北美
#>法拉利迪诺19.7 NA 145.0 175 NA NA
#>玛莎拉蒂宝来15.0北美301.0 335北美
#>沃尔沃142E 21.4不适用121.0 109不适用

您的总体思路是正确的。在使用
slice_max()
并重新整形为宽数据之前,您可以先旋转到长数据并按行号分组:

library(dplyr)
library(tidyr)
library(tibble)

mtcars %>% 
  rowid_to_column() %>%
  pivot_longer(-rowid) %>% 
  group_by(rowid) %>%
  mutate(value = replace(value, !value %in% tail(value[order(value)], 3), NA)) %>%
  pivot_wider(names_from = name, values_from = value)

# A tibble: 32 x 11
     mpg cyl    disp    hp drat  wt     qsec vs    am    gear  carb 
   <dbl> <lgl> <dbl> <dbl> <lgl> <lgl> <dbl> <lgl> <lgl> <lgl> <lgl>
 1  21   NA     160    110 NA    NA     NA   NA    NA    NA    NA   
 2  21   NA     160    110 NA    NA     NA   NA    NA    NA    NA   
 3  22.8 NA     108     93 NA    NA     NA   NA    NA    NA    NA   
 4  21.4 NA     258    110 NA    NA     NA   NA    NA    NA    NA   
 5  18.7 NA     360    175 NA    NA     NA   NA    NA    NA    NA   
 6  NA   NA     225    105 NA    NA     20.2 NA    NA    NA    NA   
 7  NA   NA     360    245 NA    NA     15.8 NA    NA    NA    NA   
 8  24.4 NA     147.    62 NA    NA     NA   NA    NA    NA    NA   
 9  NA   NA     141.    95 NA    NA     22.9 NA    NA    NA    NA   
10  19.2 NA     168.   123 NA    NA     NA   NA    NA    NA    NA   
# ... with 22 more rows
库(dplyr)
图书馆(tidyr)
图书馆(tibble)
mtcars%>%
rowid_到_列()%>%
枢轴长度(-rowid)%>%
分组依据(rowid)%>%
变异(值=替换(值,!值%在%tail中(值[顺序(值)],3),NA))%>%
枢轴(名称从=名称,值从=值)
#一个tibble:32x11
mpg气缸显示hp drat wt qsec与am齿轮carb
1 21 NA 160 110 NA NA NA NA NA NA
2 21 NA 160 110 NA NA NA NA NA
3 22.8 NA 108 93 NA NA NA NA
4 21.4 NA 258 110 NA NA NA
5 18.7 NA 360 175 NA NA NA NA NA
6钠225钠105钠20.2钠
7 NA 360 245 NA 15.8 NA NA NA
824.4不适用147.62不适用
9钠141.95钠22.9钠
10 19.2 NA 168.123 NA NA NA NA
#…还有22排

看到您对其他解决方案很好奇

在这里,我为您提供了一个更加面向
的解决方案

library(purrr)
library(dplyr)

mtcars %>% pmap_dfr(~c(...) %>% replace(rank(desc(.)) > 3, NA))

#> # A tibble: 32 x 11
#>      mpg   cyl  disp    hp  drat    wt  qsec    vs    am  gear  carb
#>    <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
#>  1  21      NA  160    110    NA    NA  NA      NA    NA    NA    NA
#>  2  21      NA  160    110    NA    NA  NA      NA    NA    NA    NA
#>  3  22.8    NA  108     93    NA    NA  NA      NA    NA    NA    NA
#>  4  21.4    NA  258    110    NA    NA  NA      NA    NA    NA    NA
#>  5  18.7    NA  360    175    NA    NA  NA      NA    NA    NA    NA
#>  6  NA      NA  225    105    NA    NA  20.2    NA    NA    NA    NA
#>  7  NA      NA  360    245    NA    NA  15.8    NA    NA    NA    NA
#>  8  24.4    NA  147.    62    NA    NA  NA      NA    NA    NA    NA
#>  9  NA      NA  141.    95    NA    NA  22.9    NA    NA    NA    NA
#> 10  19.2    NA  168.   123    NA    NA  NA      NA    NA    NA    NA
#> # ... with 22 more rows
你也可以写:

mtcars %>% pmap_dfr(function(...) c(...) %>% replace(rank(desc(.)) > 3, NA))
这三个点基本上汇集了您提供给函数的所有输入。我没有为每个输入编写变量,而是使用
将它们全部包含在内

pmap
将列表列表或向量列表作为第一个参数。 在本例中,它采用data.frame,它实际上是相同长度的向量列表

然后,
pmap
为函数提供列表中每个向量的第i个元素

截取所有这些第i个元素并
c()
创建这些元素的唯一向量

函数本身将以与公认的解决方案非常相似的方式替换该向量中的NAs。我使用了
rank
,因为在我看来它更易于阅读,但我想这是一个风格问题

pmap
始终返回一个列表。也就是说,您可以使用
pmap\u dfr
来返回数据帧。具体来说,您希望通过将最终结果的每个向量绑定为行来创建数据帧(这解释了末尾的
r


查看
?pmap
了解更多信息。

一个
dplyr
选项可以是:

mtcars %>% 
 rowwise() %>%
 mutate(temp = list(tail(sort(c_across(everything())), 3))) %>%
 ungroup() %>%
 mutate(across(everything(), ~ replace(.x, !.x %in% unlist(temp), NA))) %>%
 select(-temp)

     mpg   cyl  disp    hp  drat    wt  qsec    vs    am  gear  carb
   <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
 1  21      NA  160    110    NA    NA  NA      NA    NA    NA    NA
 2  21      NA  160    110    NA    NA  NA      NA    NA    NA    NA
 3  22.8    NA  108     93    NA    NA  NA      NA    NA    NA    NA
 4  21.4    NA  258    110    NA    NA  NA      NA    NA    NA    NA
 5  18.7    NA  360    175    NA    NA  NA      NA    NA    NA    NA
 6  NA      NA  225    105    NA    NA  20.2    NA    NA    NA    NA
 7  NA      NA  360    245    NA    NA  15.8    NA    NA    NA    NA
 8  24.4    NA  147.    62    NA    NA  NA      NA    NA    NA    NA
 9  22.8    NA  141.    95    NA    NA  22.9    NA    NA    NA    NA
10  19.2    NA  168.   123    NA    NA  NA      NA    NA    NA    NA

A
数据表
完整性解决方案:

DT <- as.data.table(mtcars)
DT[, 
   {
    t3 <- sort(unlist(.SD), decreasing = TRUE)[1:3]
    lapply(.SD, function(x) if (x %in% t3) x else NA_real_)
   }, 
   by = seq_len(nrow(DT))]

#    seq_len  mpg cyl  disp  hp drat wt  qsec vs am gear carb
# 1:       1 21.0  NA 160.0 110   NA NA    NA NA NA   NA   NA
# 2:       2 21.0  NA 160.0 110   NA NA    NA NA NA   NA   NA
# 3:       3 22.8  NA 108.0  93   NA NA    NA NA NA   NA   NA
# 4:       4 21.4  NA 258.0 110   NA NA    NA NA NA   NA   NA
# 5:       5 18.7  NA 360.0 175   NA NA    NA NA NA   NA   NA
# 6:       6   NA  NA 225.0 105   NA NA 20.22 NA NA   NA   NA
# ...

DT谢谢你指导我找到这个解决方案,从两个答案中都学到了很多东西为什么是slice_max而不是top_n,会有什么不同吗?
top_n()
已经被取代了
mtcars %>% 
 pmap_dfr(~ replace(c(...), !c(...) %in% tail(sort(c(...)), 3), NA))
DT <- as.data.table(mtcars)
DT[, 
   {
    t3 <- sort(unlist(.SD), decreasing = TRUE)[1:3]
    lapply(.SD, function(x) if (x %in% t3) x else NA_real_)
   }, 
   by = seq_len(nrow(DT))]

#    seq_len  mpg cyl  disp  hp drat wt  qsec vs am gear carb
# 1:       1 21.0  NA 160.0 110   NA NA    NA NA NA   NA   NA
# 2:       2 21.0  NA 160.0 110   NA NA    NA NA NA   NA   NA
# 3:       3 22.8  NA 108.0  93   NA NA    NA NA NA   NA   NA
# 4:       4 21.4  NA 258.0 110   NA NA    NA NA NA   NA   NA
# 5:       5 18.7  NA 360.0 175   NA NA    NA NA NA   NA   NA
# 6:       6   NA  NA 225.0 105   NA NA 20.22 NA NA   NA   NA
# ...