2010-08-09 141 views
68

当我看R软件包的来源时,我看到功能扫描经常使用。 有些时候,如果一个简单的函数在其他时候已经足够(例如“应用”), 就可以使用它,但不可能确切知道它在做什么,而不需要花费相当多的时间来遍历它所在的代码块。如何使用R功能'扫描'

我可以使用更简单的函数重现扫描效果的事实表明我不明白扫描的核心用例,而且这个函数经常使用的事实表明它非常有用。

上下文:

是R中的标准库函数;它的方法签名是:

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 

正如你所看到的,方法签名类似于“应用”虽然“扫”需要 一个参数,“STATS”。

另一个关键的区别是,“扫描”返回相同的形状作为输入数组的数组,而由“应用”返回的结果取决于传入的功能。

在动作扫

# 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 

所以总之,我要找的是一个典型的用例或两个

请不要背诵或链接到R文档,邮件列表或任何“主要”R来源 - 假设我已经阅读过它们。我感兴趣的是经验丰富的R程序员/分析师在自己的代码中使用扫描

+2

M-DX不复制您的结果。你是在自问自答。 – John 2010-08-10 00:59:59

+0

我可以计算出这个结果的'apply'的唯一用法就像't(apply(t(M),2, - - ,,dx))',但这很糟糕。 – 2011-05-04 14:32:48

回答

56

sweep通常用于按行或按列操作矩阵,并且操作的另一个输入对于每个行/列是不同的值。无论您是按行还是按列操作,均由MARGIN定义,适用。用于我称为“其他输入”的值由STATS定义。 因此,对于每一行(或列),您将从STATS中获取一个值并将其用于由FUN定义的操作。

举例来说,如果你想加1,第1行,2〜2次,等等......你所定义的矩阵,你会做什么:

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

坦白说,我不明白在R文档中定义,我只是通过查找示例来了解。

+0

稍微解释一下:'STATS'似乎是这个变量的一个不好的标签。这是“FUN”的输入,用于修改矩阵中每个元素的值(在本例中为“M”)。 STATS可以是一个常量,也可以是一个大小与所选MARGIN大小相匹配的列表/矢量等。我认为。 – Roland 2017-12-28 03:54:24

14

扫描()可以是大的用于系统性操纵由行通过柱大矩阵任一列或行,如下所示:

> 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 

当然,本实施例中是简单的,但改变STATS和FUN论点,其他操作是可能的。

6

这个问题有点旧,但由于我最近遇到过这个问题,典型的扫描使用可以在用于计算加权协方差矩阵的统计函数cov.wt的源代码中找到。我正在研究R 3.0.1中的代码。这里用sweep在计算协方差之前减去列平均值。对码的19行定心矢量导出:

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

和上线54被扫出矩阵

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

代码的作者使用默认值FUN = "-",这困惑了我一会儿。

1

您可以使用sweep函数来缩放和居中数据,如下面的代码。需要注意的是meanssds是任意位置(您可能必须要标准化,基于它们的数据有一定的参考值):

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 

此代码转换的原始分数,以T值(均值= 50和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 
+0

如果你要扩展和居中,你为什么不使用'scale()'......? – 2014-09-22 22:25:11

+1

@BenBolker正如我在答案中提到的那样,因为我可能想根据参考均值和sd来缩放项目,而不是当前样本本身的均值和sd。当您处理在大样本中进行管理和标准化的测试时,会出现这种情况,并且您希望根据统计信息将小样本分数标准化。 – ehsan88 2014-09-23 14:57:53

1

的一个用途是,当你计算加权资金用于数组。其中rowSumscolSums可以假定为'权重= 1',那么在此之前可以使用sweep来给出加权结果。这对于具有> = 3维的数组特别有用。

这就出现了,例如按@James King的例子计算加权协方差矩阵。

下面是另一个基于目前的一个项目:

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)