2
votes

La nouvelle colonne data.table renvoie la nième valeur la plus grande d'une ligne

Mes données ressemblent à ceci:

   rank          1          2          3           4           5           6 rank_match
1:    3 -0.6264538  0.3295078  0.5757814 -0.62124058 -0.01619026  0.91897737  0.3295078
2:    4  0.1836433 -0.8204684 -0.3053884 -2.21469989  0.94383621  0.78213630 -0.3053884
3:    2 -0.8356286  0.4874291  1.5117812  1.12493092  0.82122120  0.07456498  1.1249309
4:    1  1.5952808  0.7383247  0.3898432 -0.04493361  0.59390132 -1.98935170  1.5952808

Je voudrais ajouter une nouvelle colonne rank_match qui trouve la nième (prise à partir du rang colonne) la plus grande valeur de la ligne des colonnes nommées 1 à 6 . Par exemple, la première ligne chercherait la troisième plus grande valeur de la ligne des colonnes nommées 1 à 6 , soit 0,3295078.

Quelque chose comme ça (mais bien sûr, cela ne fonctionne pas):

dt[,rank_match := (sort(`1`:`6`, decreasing = TRUE)[rank])]
dt[,rank_match := (sort(.SD, decreasing = TRUE)[rank]), .SDcols=`1`:`6`]

La sortie devrait ressembler à ceci:

set.seed(1)
dt <- data.table(rank=c(3,4,2,1),`1`=rnorm(4),`2`=rnorm(4),`3`=rnorm(4),`4`=rnorm(4),`5`=rnorm(4),`6`=rnorm(4))

   rank          1          2          3           4           5           6
1:    3 -0.6264538  0.3295078  0.5757814 -0.62124058 -0.01619026  0.91897737
2:    4  0.1836433 -0.8204684 -0.3053884 -2.21469989  0.94383621  0.78213630
3:    2 -0.8356286  0.4874291  1.5117812  1.12493092  0.82122120  0.07456498
4:    1  1.5952808  0.7383247  0.3898432 -0.04493361  0.59390132 -1.98935170

Merci tellement.


0 commentaires

5 Réponses :


4
votes

Une option est de grouper par séquence de lignes, spécifiez les colonnes d'intérêt à partir de la colonne 2, unlist , le sous-ensemble de Data.table, sort dans l'ordre décroissant , sous-définissez la valeur en fonction de la colonne 'rank' et attribuez-la à 'rank_match'

library(purrr)
dt[, rank_match := pmap_dbl(.SD, ~ c(...) %>% 
                                    {sort(-.[-1])[.[1]]})]

Une autre option serait de fondre puis d'obtenir le correspondant valeur de la colonne 'value'

dt[, rank_match := melt(.SD, 'rank')[, value[order(-value)[rank]], rank]$V1]

Ou une approche compacte suggérée par @IceCreamToucan

out <- melt(dt, id.var = c('rn', 'rank'))[order(-value), 
                  value[rank[1]] , .(rn)][order(rn)]$V1
dt[, rank_match := out][, rn := NULL][]

Ou utilisez pmap (de purrr ) pour parcourir les lignes

dt[, rank_match := sort(unlist(.SD), decreasing = TRUE)[rank], 
           1:nrow(dt), .SDcols = 2:ncol(dt) ]
dt
#   rank          1          2          3           4           5           6 rank_match
#1:    3 -0.6264538  0.3295078  0.5757814 -0.62124058 -0.01619026  0.91897737  0.3295078
#2:    4  0.1836433 -0.8204684 -0.3053884 -2.21469989  0.94383621  0.78213630 -0.3053884
#3:    2 -0.8356286  0.4874291  1.5117812  1.12493092  0.82122120  0.07456498  1.1249309
#4:    1  1.5952808  0.7383247  0.3898432 -0.04493361  0.59390132 -1.98935170  1.5952808


0 commentaires

3
votes

appliquer la fonction indiquée sur chaque ligne de .SD:

   rank          1          2          3           4           5           6 rank_match
1:    3 -0.6264538  0.3295078  0.5757814 -0.62124058 -0.01619026  0.91897737  0.3295078
2:    4  0.1836433 -0.8204684 -0.3053884 -2.21469989  0.94383621  0.78213630 -0.3053884
3:    2 -0.8356286  0.4874291  1.5117812  1.12493092  0.82122120  0.07456498  1.1249309
4:    1  1.5952808  0.7383247  0.3898432 -0.04493361  0.59390132 -1.98935170  1.5952808

giving:

dt[, rank_match := apply(.SD, 1, function(x) -sort(-x[-1])[x[1]])]


1 commentaires

Une autre excellente solution qui fonctionne bien @G. Grothendieck Merci.



2
votes
dt[, rank_match := apply(.SD, 1, function(x) x[order(-x)][rank]), by = rank, .SDcols = `1`:`6`]
dt
   rank          1          2          3           4           5           6 rank_match
1:    3 -0.6264538  0.3295078  0.5757814 -0.62124058 -0.01619026  0.91897737  0.3295078
2:    4  0.1836433 -0.8204684 -0.3053884 -2.21469989  0.94383621  0.78213630 -0.3053884
3:    2 -0.8356286  0.4874291  1.5117812  1.12493092  0.82122120  0.07456498  1.1249309
4:    1  1.5952808  0.7383247  0.3898432 -0.04493361  0.59390132 -1.98935170  1.5952808

1 commentaires

Merci @snoram cette réponse me semble la plus lisible, bien que toutes les autres fonctionnent également.



2
votes

DescTools :: Large renvoie les n èmes plus grands éléments d'un vecteur sans trier le tout. Je ne sais pas comment cela se compare à dt [order (-value) [rank], ...] .

library(DescTools)
library(data.table)

dt[, rank_match := melt(dt, 'rank')[, Large(value, rank)[1], rank]$V1]


#    rank          1          2          3           4           5           6 rank_match
# 1:    3 -0.6264538  0.3295078  0.5757814 -0.62124058 -0.01619026  0.91897737  0.3295078
# 2:    4  0.1836433 -0.8204684 -0.3053884 -2.21469989  0.94383621  0.78213630 -0.3053884
# 3:    2 -0.8356286  0.4874291  1.5117812  1.12493092  0.82122120  0.07456498  1.1249309
# 4:    1  1.5952808  0.7383247  0.3898432 -0.04493361  0.59390132 -1.98935170  1.5952808

Remarque: Si certaines lignes ont le même rang, vous devez utiliser la logique rn / numéro de ligne comme dans la réponse d'Akrun.


0 commentaires