Comment utiliser la fonction «balayage»

100

Quand je regarde la source des packages R, je vois la fonction sweeputilisée assez souvent. Parfois, il est utilisé lorsqu'une fonction plus simple aurait suffi (par exemple, apply), d'autres fois, il est impossible de savoir exactement ce qu'elle fait sans passer beaucoup de temps à parcourir le bloc de code dans lequel il se trouve.

Le fait que je puisse reproduire sweepl'effet de en utilisant une fonction plus simple suggère que je ne comprends pas sweeples principaux cas d'utilisation de cette fonction, et le fait que cette fonction soit utilisée si souvent suggère qu'elle est très utile.

Le contexte:

sweepest une fonction de la bibliothèque standard de R; ses arguments sont:

sweep(x, MARGIN, STATS, FUN="-", check.margin=T, ...)

# x is the data
# STATS refers to the summary statistics which you wish to 'sweep out'
# FUN is the function used to carry out the sweep, "-" is the default

Comme vous pouvez le voir, les arguments sont similaires à applybien sweepnécessite un paramètre supplémentaire , STATS.

Une autre différence clé est que sweeprenvoie un tableau de la même forme que le tableau d'entrée, alors que le résultat renvoyé par applydépend de la fonction transmise.

sweep en action:

# e.g., use 'sweep' to express a given matrix in terms of distance from 
# the respective column mean

# create some data:
M = matrix( 1:12, ncol=3)

# calculate column-wise mean for M
dx = colMeans(M)

# now 'sweep' that summary statistic from M
sweep(M, 2, dx, FUN="-")

     [,1] [,2] [,3]
[1,] -1.5 -1.5 -1.5
[2,] -0.5 -0.5 -0.5
[3,]  0.5  0.5  0.5
[4,]  1.5  1.5  1.5

Donc, en résumé, ce que je recherche, c'est un cas d'utilisation exemplaire ou deux sweep.

S'il vous plaît, ne récitez pas ou ne liez pas à la documentation R, aux listes de diffusion ou à l'une des sources R «primaires» - supposez que je les ai lues. Ce qui m'intéresse, c'est la façon dont les programmeurs / analystes R expérimentés utilisent sweepdans leur propre code.

doug
la source
2
M-dx ne reproduit pas votre résultat. Vous avez répondu à votre propre question.
John
La seule utilisation de ce applyque je peux comprendre pour ce résultat est quelque chose comme t(apply(t(M), 2, "-", dx)), mais c'est assez méchant.
Ken Williams

Réponses:

84

sweep()est généralement utilisé lorsque vous utilisez une matrice par ligne ou par colonne, et l'autre entrée de l'opération est une valeur différente pour chaque ligne / colonne. Que vous opériez par ligne ou par colonne est défini par MARGIN, comme pour apply(). Les valeurs utilisées pour ce que j'ai appelé «l'autre entrée» sont définies par STATS. Ainsi, pour chaque ligne (ou colonne), vous allez prendre une valeur de STATS et l'utiliser dans l'opération définie par FUN.

Par exemple, si vous souhaitez ajouter 1 à la 1ère ligne, 2 à la 2ème, etc. de la matrice que vous avez définie, vous allez faire:

sweep (M, 1, c(1: 4), "+")

Je n'ai franchement pas non plus compris la définition dans la documentation R, je viens de l'apprendre en recherchant des exemples.

Daniele Merico
la source
2
pour paraphraser un peu: STATSsemble être une mauvaise étiquette pour cette variable. C'est une entrée FUNqui sert à modifier la valeur de chaque élément de la matrice ( M, dans cet exemple). STATSpeut être soit une constante, soit une liste / vecteur / etc d'une taille correspondant à la taille de celle choisie MARGIN. Je pense.
Roland
16

sweep () peut être idéal pour manipuler systématiquement une grande matrice colonne par colonne ou ligne par ligne, comme indiqué ci-dessous:

> print(size)
     Weight Waist Height
[1,]    130    26    140
[2,]    110    24    155
[3,]    118    25    142
[4,]    112    25    175
[5,]    128    26    170

> sweep(size, 2, c(10, 20, 30), "+")
     Weight Waist Height
[1,]    140    46    170
[2,]    120    44    185
[3,]    128    45    172
[4,]    122    45    205
[5,]    138    46    200

Certes, cet exemple est simple, mais en changeant les arguments STATS et FUN, d'autres manipulations sont possibles.

Brad Horn
la source
6

Cette question est un peu ancienne, mais depuis que j'ai récemment rencontré ce problème, une utilisation typique du balayage peut être trouvée dans le code source de la fonction stats cov.wt, utilisée pour calculer les matrices de covariance pondérée. Je regarde le code dans R 3.0.1. Ici, il sweepest utilisé pour soustraire les moyennes des colonnes avant de calculer la covariance. À la ligne 19 du code, le vecteur de centrage est dérivé:

 center <- if (center) 
        colSums(wt * x)
    else 0

et à la ligne 54, il est balayé hors de la matrice

x <- sqrt(wt) * sweep(x, 2, center, check.margin = FALSE)

L'auteur du code utilise la valeur par défaut FUN = "-", ce qui m'a dérouté pendant un moment.

James King
la source
3

Une utilisation est lorsque vous calculez des sommes pondérées pour un tableau. Où rowSumsou colSumspeut être supposé signifier «poids = 1», sweeppeut être utilisé avant cela pour donner un résultat pondéré. Ceci est particulièrement utile pour les tableaux avec> = 3 dimensions.

Cela se produit par exemple lors du calcul d'une matrice de covariance pondérée selon l'exemple de @James King.

En voici un autre basé sur un projet en cours:

set.seed(1)
## 2x2x2 array
a1 <- array(as.integer(rnorm(8, 10, 5)), dim=c(2, 2, 2))
## 'element-wise' sum of matrices
## weights = 1
rowSums(a1, dims=2)
## weights
w1 <- c(3, 4)
## a1[, , 1] * 3;  a1[, , 2] * 4
a1 <- sweep(a1, MARGIN=3, STATS=w1, FUN="*")
rowSums(a1, dims=2)
Dardisco
la source
0

Vous pouvez utiliser la sweepfonction pour mettre à l'échelle et centrer les données comme le code suivant. Notez que meanset sdssont arbitraires ici (vous pouvez avoir des valeurs de référence que vous souhaitez normaliser les données en fonction d'elles):

df=matrix(sample.int(150, size = 100, replace = FALSE),5,5)

df_means=t(apply(df,2,mean))
df_sds=t(apply(df,2,sd))

df_T=sweep(sweep(df,2,df_means,"-"),2,df_sds,"/")*10+50

Ce code convertit les scores bruts en scores T (avec moyenne = 50 et sd = 10):

> df
     [,1] [,2] [,3] [,4] [,5]
[1,]  109    8   89   69   15
[2,]   85   13   25  150   26
[3,]   30   79   48    1  125
[4,]   56   74   23  140  100
[5,]  136  110  112   12   43
> df_T
         [,1]     [,2]     [,3]     [,4]     [,5]
[1,] 56.15561 39.03218 57.46965 49.22319 40.28305
[2,] 50.42946 40.15594 41.31905 60.87539 42.56695
[3,] 37.30704 54.98946 47.12317 39.44109 63.12203
[4,] 43.51037 53.86571 40.81435 59.43685 57.93136
[5,] 62.59752 61.95672 63.27377 41.02349 46.09661
Ehsan88
la source
1
@BenBolker comme je l'ai mentionné dans la réponse, car je peux vouloir mettre à l'échelle les éléments en fonction d'une moyenne et d'un sd de référence, et non de la moyenne et du sd de l'échantillon actuel lui-même. Cela se produit lorsque vous traitez des tests administrés et standardisés dans de grands échantillons et que vous souhaitez standardiser votre score de petit échantillon en fonction de leurs statistiques.
Ehsan88