保持连续前 3 个值,将其他所有内容更改为 NA

Vai*_*ngh 13 r dplyr tidyverse

使用 mtcars 实现可重复性

(这是一个行操作)。我想根据它们的大小连续保留 3 个值(所以基本上前 3 个值将具有价值,其余的一切都更改为 NA)

我尝试使用 pivot_longer 转换为 long 然后过滤,但问题是我想再次转换为宽,因为我想保留数据的结构。

   mtcars %>% 
    pivot_longer(cols = everything()) %>% 
    group_by(name) %>% top_n(3) 
Run Code Online (Sandbox Code Playgroud)

3 行 mtcars 上的示例输出以下

注意:在 mtcars 中,所有 3 行都具有与非 NA 相同的列名值,但在原始数据集中会有所不同。(最好是tidyverse解决方案)

All*_*ron 8

我知道你想要一个 tidyverse 解决方案,但这是一个基于 R 的单行:

t(apply(mtcars, 1, function(x) {x[order(x)[1:(length(x) - 3)]] <- NA; x}))
#>                      mpg cyl  disp  hp drat wt  qsec vs am gear carb
#> Mazda RX4           21.0  NA 160.0 110   NA NA    NA NA NA   NA   NA
#> Mazda RX4 Wag       21.0  NA 160.0 110   NA NA    NA NA NA   NA   NA
#> Datsun 710          22.8  NA 108.0  93   NA NA    NA NA NA   NA   NA
#> Hornet 4 Drive      21.4  NA 258.0 110   NA NA    NA NA NA   NA   NA
#> Hornet Sportabout   18.7  NA 360.0 175   NA NA    NA NA NA   NA   NA
#> Valiant               NA  NA 225.0 105   NA NA 20.22 NA NA   NA   NA
#> Duster 360            NA  NA 360.0 245   NA NA 15.84 NA NA   NA   NA
#> Merc 240D           24.4  NA 146.7  62   NA NA    NA NA NA   NA   NA
#> Merc 230              NA  NA 140.8  95   NA NA 22.90 NA NA   NA   NA
#> Merc 280            19.2  NA 167.6 123   NA NA    NA NA NA   NA   NA
#> Merc 280C             NA  NA 167.6 123   NA NA 18.90 NA NA   NA   NA
#> Merc 450SE            NA  NA 275.8 180   NA NA 17.40 NA NA   NA   NA
#> Merc 450SL            NA  NA 275.8 180   NA NA 17.60 NA NA   NA   NA
#> Merc 450SLC           NA  NA 275.8 180   NA NA 18.00 NA NA   NA   NA
#> Cadillac Fleetwood    NA  NA 472.0 205   NA NA 17.98 NA NA   NA   NA
#> Lincoln Continental   NA  NA 460.0 215   NA NA 17.82 NA NA   NA   NA
#> Chrysler Imperial     NA  NA 440.0 230   NA NA 17.42 NA NA   NA   NA
#> Fiat 128            32.4  NA  78.7  66   NA NA    NA NA NA   NA   NA
#> Honda Civic         30.4  NA  75.7  52   NA NA    NA NA NA   NA   NA
#> Toyota Corolla      33.9  NA  71.1  65   NA NA    NA NA NA   NA   NA
#> Toyota Corona       21.5  NA 120.1  97   NA NA    NA NA NA   NA   NA
#> Dodge Challenger      NA  NA 318.0 150   NA NA 16.87 NA NA   NA   NA
#> AMC Javelin           NA  NA 304.0 150   NA NA 17.30 NA NA   NA   NA
#> Camaro Z28            NA  NA 350.0 245   NA NA 15.41 NA NA   NA   NA
#> Pontiac Firebird    19.2  NA 400.0 175   NA NA    NA NA NA   NA   NA
#> Fiat X1-9           27.3  NA  79.0  66   NA NA    NA NA NA   NA   NA
#> Porsche 914-2       26.0  NA 120.3  91   NA NA    NA NA NA   NA   NA
#> Lotus Europa        30.4  NA  95.1 113   NA NA    NA NA NA   NA   NA
#> Ford Pantera L      15.8  NA 351.0 264   NA NA    NA NA NA   NA   NA
#> Ferrari Dino        19.7  NA 145.0 175   NA NA    NA NA NA   NA   NA
#> Maserati Bora       15.0  NA 301.0 335   NA NA    NA NA NA   NA   NA
#> Volvo 142E          21.4  NA 121.0 109   NA NA    NA NA NA   NA   NA
Run Code Online (Sandbox Code Playgroud)


H 1*_*H 1 8

你的总体思路是正确的。在使用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
Run Code Online (Sandbox Code Playgroud)


Edo*_*Edo 6

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

在这里,我给你留下了一个更tidyverse面向的解决方案。

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
Run Code Online (Sandbox Code Playgroud)

作为一个概念,它类似于baseR 解决方案,但它应该(或至少尝试)更具“功能性”并希望具有可读性。即使选择的解决方案看起来非常好。

编辑。

要回答您对更多信息的评论..

应该知道,这~有助于您编写更紧凑的匿名函数。

代替:

mtcars %>% pmap_dfr(~c(...) %>% replace(rank(desc(.)) > 3, NA))
Run Code Online (Sandbox Code Playgroud)

你也可以写:

mtcars %>% pmap_dfr(function(...) c(...) %>% replace(rank(desc(.)) > 3, NA))
Run Code Online (Sandbox Code Playgroud)

这三个点基本上将您提供给函数的所有输入聚集在一起。我没有为每个输入编写一个变量,而是...将它们全部包含在内。

pmap将列表列表或向量列表作为第一个参数。在这种情况下,它需要一个 data.frame,它实际上是一个相同长度的向量列表。

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

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

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

pmap总是返回一个列表。那是你可以pmap_dfr用来返回数据帧的。具体来说,您希望通过将最终结果的每个向量绑定为行来创建数据帧(最后解释了r)。

查看?pmap更多信息。