如何解决连续保留前三个值,将其他所有内容更改为NA
使用mtcar进行再现性
(这是一个行操作)。我想根据其大小连续保留3个值(因此,基本上前3个值将具有值,其余全部更改为NA)
我尝试使用ivot_longer转换为长然后过滤,但问题是我想再次转换为宽,因为我想保留数据结构。
mtcars %>%
pivot_longer(cols = everything()) %>%
group_by(name) %>% top_n(3)
注意:在mtcars中,所有3行的列名值都与非NA相同,但在原始数据集中会有所不同。 (最好是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
,
您的总体思路是正确的。在使用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
,
看到您对其他解决方案感到好奇。
在这里,我给您提供一种更加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
从概念上讲,它类似于base
R解决方案,但它应该(或至少试图)更具“功能性”并希望可读性强。即使选择的解决方案看起来很好。
编辑。
回答您对更多信息的评论。
应该知道~
可帮助您编写更紧凑的匿名函数。
代替:
mtcars %>% pmap_dfr(~c(...) %>% replace(rank(desc(.)) > 3,NA))
您还可以写:
mtcars %>% pmap_dfr(function(...) c(...) %>% replace(rank(desc(.)) > 3,NA))
这三个点基本上将您提供给函数的输入汇总在一起。我没有为每个输入编写变量,而是使用...
来将它们全部包含在内。
pmap
将列表列表或向量列表作为第一个参数。
在这种情况下,它需要一个data.frame,它实际上是相同长度的向量的列表。
然后,pmap
为函数提供列表中每个向量的第i个元素。
...
拦截所有第i个元素,c()
创建这些元素的唯一矢量。
函数本身将以与接受的解决方案非常相似的方式替换该向量中的NA。我使用rank
是因为它在我看来似乎更容易阅读,但我想这只是样式问题。
pmap
始终返回列表。那就是您可以使用pmap_dfr
返回一个数据帧。具体来说,您想通过将最终结果的每个向量作为行绑定来创建数据帧(这在末尾说明了r
。
查看?pmap
了解更多信息。
一种data.table
完整性解决方案:
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
# ...
,
一个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
使用purrr
的相同逻辑:
mtcars %>%
pmap_dfr(~ replace(c(...),!c(...) %in% tail(sort(c(...)),NA))
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。