Функции группировки (Tapply, by, Aggregate) и *Применить семью
Вопрос
Всякий раз, когда я хочу сделать что -то «карту» py в R, я обычно стараюсь использовать функцию в apply
семья.
Однако я никогда не понимал различий между ними - как {sapply
, lapply
, и т. д.} Примените функцию к входу/сгруппированному входу, как будет выглядеть выход или даже какой может быть ввод - поэтому я часто просто прохожу их все, пока не получу то, что хочу.
Может кто-нибудь объяснить, как использовать, какой из них, когда?
Мой нынешний (вероятно, неверный / неполный) понимание ...
sapply(vec, f)
: Ввод - это вектор. Вывод - это вектор / матрица, где элементi
являетсяf(vec[i])
, давая вам матрицу, еслиf
имеет многоэлементный выходlapply(vec, f)
: такой же какsapply
, но выход - это список?apply(matrix, 1/2, f)
: Ввод - это матрица. Выход - это вектор, где элементi
это f (ряд/col I из матрицы)tapply(vector, grouping, f)
: Выходная матрица / массив, где элемент в матрице / массиве является значениемf
на группировкеg
вектора, а такжеg
оттолкнутся к имена ряд / сby(dataframe, grouping, f)
: позволятьg
быть группировкой. применятьf
каждому столбцу группы / dataframe. довольно печатать группировку и ценностьf
на каждом столбце.aggregate(matrix, grouping, f)
: похожий наby
, но вместо того, чтобы довольно печатать вывод, совокупность падает все в DataFrame.
Вопрос на сторону: я до сих пор не выучил Plyr или Reshigeape - будет plyr
или reshape
Замените все эти цели полностью?
Решение
R имеет много * применять функции, которые умело описаны в справочных файлах (например, ?apply
) Их достаточно, однако, что начинающие пользователи могут испытывать трудности, решая, какой из них подходит для их ситуации или даже вспоминая их всех. Они могут иметь общее смысл, что «я должен использовать функцию * применить здесь», но может быть трудно держать их всех прямо сначала.
Несмотря на то, что указано в других ответах), что большая часть функциональности * применения семьи покрыта чрезвычайно популярным plyr
Пакет, базовые функции остаются полезными и достойными знания.
Этот ответ предназначен как своего рода указатель Для новых пользователей, чтобы помочь им направить правильную *применить функцию для их конкретной проблемы. Обратите внимание, это нет Предназначен просто регулировать или заменить документацию R! Надежда заключается в том, что этот ответ поможет вам решить, какой * применить функцию подходит вашей ситуации, а затем решать вам, чтобы исследовать его дальше. С одним исключением различия в производительности не будут решены.
применять - Когда вы хотите применить функцию на строки или столбцы матрицы (и аналоги более высокого размера); Как правило, не рекомендуется для кадров данных, поскольку она принесет к матрицу в первую очередь.
# Two dimensional matrix M <- matrix(seq(1,16), 4, 4) # apply min to rows apply(M, 1, min) [1] 1 2 3 4 # apply max to columns apply(M, 2, max) [1] 4 8 12 16 # 3 dimensional array M <- array( seq(32), dim = c(4,4,2)) # Apply sum across each M[*, , ] - i.e Sum across 2nd and 3rd dimension apply(M, 1, sum) # Result is one-dimensional [1] 120 128 136 144 # Apply sum across each M[*, *, ] - i.e Sum across 3rd dimension apply(M, c(1,2), sum) # Result is two-dimensional [,1] [,2] [,3] [,4] [1,] 18 26 34 42 [2,] 20 28 36 44 [3,] 22 30 38 46 [4,] 24 32 40 48
Если вы хотите, чтобы строки/столбцы средств или суммы для 2D-матрицы, обязательно изучите высоко оптимизированную, молниеносную Quick
colMeans
,rowMeans
,colSums
,rowSums
.Лаппли - Если вы хотите применить функцию к каждому элементу списка по очереди и вернуть список.
Это рабочая лошадка многих других функций * применения. Описать свой код, и вы часто найдете
lapply
под.x <- list(a = 1, b = 1:3, c = 10:100) lapply(x, FUN = length) $a [1] 1 $b [1] 3 $c [1] 91 lapply(x, FUN = sum) $a [1] 1 $b [1] 6 $c [1] 5005
накладное - Когда вы хотите применить функцию в каждый элемент списка в свою очередь, но вы хотите вектор назад, а не список.
Если вы найдете себя ввода
unlist(lapply(...))
, остановитесь и рассмотримsapply
.x <- list(a = 1, b = 1:3, c = 10:100) # Compare with above; a named vector, not a list sapply(x, FUN = length) a b c 1 3 91 sapply(x, FUN = sum) a b c 1 6 5005
В более продвинутых использования
sapply
Он попытается принуждать к результату многомерного массива, если это необходимо. Например, если наша функция возвращает векторы одинаковой длины,sapply
будет использовать их в качестве столбцов матрицы:sapply(1:5,function(x) rnorm(3,x))
Если наша функция возвращает 2-мерную матрицу,
sapply
будет делать по сути то же самое, лечение каждой возвращенной матрицы как одно длительное вектор:sapply(1:5,function(x) matrix(x,2,2))
Если мы не указаем
simplify = "array"
, в этом случае он будет использовать отдельные матрицы для построения многомерного массива:sapply(1:5,function(x) matrix(x,2,2), simplify = "array")
Каждое из этих поведений, конечно, зависит от нашей функции, возвращающейся векторами или матрицами одинаковой длины или измерения.
vapply - Когда вы хотите использовать
sapply
Но, возможно, нужно выжать еще несколько скоростей из вашего кода.За
vapply
, Вы в основном приводят R пример того, какую вещь вернет ваша функция, которая может сэкономить некоторое время, принуждающее возвращаемые значения, чтобы соответствовать одному атомному вектору.x <- list(a = 1, b = 1:3, c = 10:100) #Note that since the advantage here is mainly speed, this # example is only for illustration. We're telling R that # everything returned by length() should be an integer of # length 1. vapply(x, FUN = length, FUN.VALUE = 0L) a b c 1 3 91
мрачный - Для того, когда у вас есть несколько структур данных (например, векторов, списков), и вы хотите применить функцию на 1-й элементы каждого, а затем 2-й элементы каждого и т. Д., Принудительный результат к вектору / массиву, как в
sapply
.Это многомерное в том смысле, что ваша функция должна принимать несколько аргументов.
#Sums the 1st elements, the 2nd elements, etc. mapply(sum, 1:5, 1:5, 1:5) [1] 3 6 9 12 15 #To do rep(1,4), rep(2,3), etc. mapply(rep, 1:4, 4:1) [[1]] [1] 1 1 1 1 [[2]] [1] 2 2 2 [[3]] [1] 3 3 [[4]] [1] 4
карта - Обертка к
mapply
сSIMPLIFY = FALSE
, поэтому он гарантированно вернет список.Map(sum, 1:5, 1:5, 1:5) [[1]] [1] 3 [[2]] [1] 6 [[3]] [1] 9 [[4]] [1] 12 [[5]] [1] 15
rapply. - Ибо когда вы хотите применить функцию для каждого элемента вложенный список структура рекурсивно.
Чтобы дать вам некоторое представление о том, как необычно
rapply
Я забыл об этом, когда сначала публиковать этот ответ! Очевидно, я уверен, что многие люди используют это, но YMMV.rapply
Лучше всего иллюстрируется пользовательской функцией для применения:# Append ! to string, otherwise increment myFun <- function(x){ if(is.character(x)){ return(paste(x,"!",sep="")) } else{ return(x + 1) } } #A nested list structure l <- list(a = list(a1 = "Boo", b1 = 2, c1 = "Eeek"), b = 3, c = "Yikes", d = list(a2 = 1, b2 = list(a3 = "Hey", b3 = 5))) # Result is named vector, coerced to character rapply(l, myFun) # Result is a nested list like l, with values altered rapply(l, myFun, how="replace")
ТАППЛИ - Когда вы хотите применить функцию к подвеска вектора и подмножества определяются некоторыми другими вектором, как правило, является фактором.
Черные овцы * применяют семью, родами. Использование файла справки фразы «рваный массив» может быть немного сбивает с толку, но на самом деле это довольно просто.
Вектор:
x <- 1:20
Фактор (та же длины!) Определяющий группы:
y <- factor(rep(letters[1:5], each = 4))
Сожмите значения в
x
в каждой подгруппе, определеннойy
:tapply(x, y, sum) a b c d e 10 26 42 58 74
Можно обрабатывать более сложные примеры, где подгруппы определяются уникальными комбинациями списка нескольких факторов.
tapply
похоже в духе к функциям с разделением приложения, которые распространены в R (aggregate
,by
,ave
,ddply
, и т. д.) отсюда и статус черной овцы.
Другие советы
На боковой записке вот как разные plyr
Функции соответствуют базу *apply
Функции (от вступления в документ Plyr с веб -страницы Plyr http://had.co.nz/plyr/)
Base function Input Output plyr function
---------------------------------------
aggregate d d ddply + colwise
apply a a/l aaply / alply
by d l dlply
lapply l l llply
mapply a a/l maply / mlply
replicate r a/l raply / rlply
sapply l a laply
Одна из целей plyr
заключается в том, чтобы обеспечить согласованные соглашения об именах для каждой из функций, кодируя входные и выходные типы данных в имени функции. Он также обеспечивает согласованность в выводе, в этом выходе из dlply()
легко проходимо к ldply()
производить полезный вывод и т. Д.
Концептуально, обучение plyr
не сложнее, чем понимание базы *apply
Функции.
plyr
и reshape
Функции заменили почти все эти функции в моем повседневном использовании. Но также от вступления в документ Plyr:
Связанные функции
tapply
иsweep
не иметь соответствующей функции вplyr
, и оставайтесь полезными.merge
полезен для сочетания резюме с исходными данными.
Из слайда 21 из http://www.slideshare.net/hadley/plyr-one-data-analytic-strategy:
(Надеюсь, ясно, что apply
соответствует @ Хэдли aaply
и aggregate
соответствует @ Хэдли ddply
И т. Д. Слайд 20 того же SlideShare будет уточнить, если вы не получите его с этого изображения.)
(Слева вход, сверху вывод)
Сначала начните с Отличный ответ Джорана - сомнительно, что угодно может лучше этого.
Затем следующая Mnemonics может помочь запомнить различия между каждым. Хотя некоторые очевидны, другие могут быть меньше так --- для них вы найдете оправдание в дискуссиях Джорана.
Мнемоника
lapply
это список Применить, который действует в списке или вектор и возвращает список.sapply
это простоlapply
(Функция по умолчанию возвращает вектор или матрицу, когда это возможно)vapply
это Проверено применимо (позволяет предопределить тип объекта возврата)rapply
это рекурсивный Подать заявку на вложенные списки, то есть списки в спискахtapply
это Tagged Применить там, где теги идентифицируют подмножестваapply
является розыгрыш: Применяет функцию на строки или столбцы матрицы (или, в целом, чтобы размеры массива)
Создание правильного фона
При использовании apply
Семья все еще чувствует себя немного чужой вам, тогда это может быть, что вы не пропустите ключевую точку зрения.
Эти две статьи могут помочь. Они предоставляют необходимый фон для мотивации Методы функционального программирования которые предоставляются apply
Семья функций.
Пользователи Lisp распознают парадигму немедленно. Если вы не знакомы с Lisp, как только вы получите голову вокруг FP, вы получите мощную точку зрения для использования в R - и apply
сделает намного больше смысла.
- Продвинутый R: функциональное программирование, Хэдли Уикхем
- Простое функциональное программирование в R, Майкл Бартон
Поскольку я понял, что (очень превосходные) ответы на этот пост отсутствует by
и aggregate
Объяснения. Вот мой вклад.
ПО
То by
функция, как указано в документации, может быть, как «обертка» для tapply
. Анкет Сила by
возникает, когда мы хотим вычислить задачу, которая tapply
Не могу справиться. Одним из примеров является этот код:
ct <- tapply(iris$Sepal.Width , iris$Species , summary )
cb <- by(iris$Sepal.Width , iris$Species , summary )
cb
iris$Species: setosa
Min. 1st Qu. Median Mean 3rd Qu. Max.
2.300 3.200 3.400 3.428 3.675 4.400
--------------------------------------------------------------
iris$Species: versicolor
Min. 1st Qu. Median Mean 3rd Qu. Max.
2.000 2.525 2.800 2.770 3.000 3.400
--------------------------------------------------------------
iris$Species: virginica
Min. 1st Qu. Median Mean 3rd Qu. Max.
2.200 2.800 3.000 2.974 3.175 3.800
ct
$setosa
Min. 1st Qu. Median Mean 3rd Qu. Max.
2.300 3.200 3.400 3.428 3.675 4.400
$versicolor
Min. 1st Qu. Median Mean 3rd Qu. Max.
2.000 2.525 2.800 2.770 3.000 3.400
$virginica
Min. 1st Qu. Median Mean 3rd Qu. Max.
2.200 2.800 3.000 2.974 3.175 3.800
Если мы распечатаем эти два объекта, ct
и cb
, Мы «по сути» имеют одинаковые результаты, и единственные различия в том, как они показаны и разные class
атрибуты соответственно by
за cb
и array
за ct
.
Как я уже сказал, сила by
возникает, когда мы не можем использовать tapply
; Следующий код является одним из примеров:
tapply(iris, iris$Species, summary )
Error in tapply(iris, iris$Species, summary) :
arguments must have same length
Г говорит, что аргументы должны иметь одинаковую длину, говорят: «Мы хотим рассчитать summary
из всех переменных в iris
вдоль фактора Species
«: Но R просто не могу сделать это, потому что он не знает, как справиться.
С by
Функция R отправляет определенный метод для data frame
класс, а затем пусть summary
Функция работает, даже если длина первого аргумента (и тип тоже) отличается.
bywork <- by(iris, iris$Species, summary )
bywork
iris$Species: setosa
Sepal.Length Sepal.Width Petal.Length Petal.Width Species
Min. :4.300 Min. :2.300 Min. :1.000 Min. :0.100 setosa :50
1st Qu.:4.800 1st Qu.:3.200 1st Qu.:1.400 1st Qu.:0.200 versicolor: 0
Median :5.000 Median :3.400 Median :1.500 Median :0.200 virginica : 0
Mean :5.006 Mean :3.428 Mean :1.462 Mean :0.246
3rd Qu.:5.200 3rd Qu.:3.675 3rd Qu.:1.575 3rd Qu.:0.300
Max. :5.800 Max. :4.400 Max. :1.900 Max. :0.600
--------------------------------------------------------------
iris$Species: versicolor
Sepal.Length Sepal.Width Petal.Length Petal.Width Species
Min. :4.900 Min. :2.000 Min. :3.00 Min. :1.000 setosa : 0
1st Qu.:5.600 1st Qu.:2.525 1st Qu.:4.00 1st Qu.:1.200 versicolor:50
Median :5.900 Median :2.800 Median :4.35 Median :1.300 virginica : 0
Mean :5.936 Mean :2.770 Mean :4.26 Mean :1.326
3rd Qu.:6.300 3rd Qu.:3.000 3rd Qu.:4.60 3rd Qu.:1.500
Max. :7.000 Max. :3.400 Max. :5.10 Max. :1.800
--------------------------------------------------------------
iris$Species: virginica
Sepal.Length Sepal.Width Petal.Length Petal.Width Species
Min. :4.900 Min. :2.200 Min. :4.500 Min. :1.400 setosa : 0
1st Qu.:6.225 1st Qu.:2.800 1st Qu.:5.100 1st Qu.:1.800 versicolor: 0
Median :6.500 Median :3.000 Median :5.550 Median :2.000 virginica :50
Mean :6.588 Mean :2.974 Mean :5.552 Mean :2.026
3rd Qu.:6.900 3rd Qu.:3.175 3rd Qu.:5.875 3rd Qu.:2.300
Max. :7.900 Max. :3.800 Max. :6.900 Max. :2.500
Это действительно работает, и результат очень удивителен. Это объект класса by
это вместе Species
(скажем, для каждого из них) вычисляет summary
каждой переменной.
Обратите внимание, что если первый аргумент является data frame
, отправленная функция должна иметь метод для этого класса объектов. Например, мы используем этот код с mean
Функция у нас будет этот код, у которого нет смысла вообще:
by(iris, iris$Species, mean)
iris$Species: setosa
[1] NA
-------------------------------------------
iris$Species: versicolor
[1] NA
-------------------------------------------
iris$Species: virginica
[1] NA
Warning messages:
1: In mean.default(data[x, , drop = FALSE], ...) :
argument is not numeric or logical: returning NA
2: In mean.default(data[x, , drop = FALSE], ...) :
argument is not numeric or logical: returning NA
3: In mean.default(data[x, , drop = FALSE], ...) :
argument is not numeric or logical: returning NA
Совокупный
aggregate
можно рассматривать как другой другой способ использования tapply
Если мы используем это таким образом.
at <- tapply(iris$Sepal.Length , iris$Species , mean)
ag <- aggregate(iris$Sepal.Length , list(iris$Species), mean)
at
setosa versicolor virginica
5.006 5.936 6.588
ag
Group.1 x
1 setosa 5.006
2 versicolor 5.936
3 virginica 6.588
Две непосредственные различия заключаются в том, что второй аргумент aggregate
должен быть списком, пока tapply
могу (не обязательно) быть списком и что вывод aggregate
это кадр данных в то время как один из tapply
является array
.
Сила aggregate
это то, что он может легко обрабатывать подмножества данных с subset
аргумент и что у него есть методы для ts
объекты и formula
также.
Эти элементы делают aggregate
легче работать с этим tapply
в некоторых ситуациях. Вот несколько примеров (доступных в документации):
ag <- aggregate(len ~ ., data = ToothGrowth, mean)
ag
supp dose len
1 OJ 0.5 13.23
2 VC 0.5 7.98
3 OJ 1.0 22.70
4 VC 1.0 16.77
5 OJ 2.0 26.06
6 VC 2.0 26.14
Мы можем достичь того же с tapply
Но синтаксис немного сложнее и выход (в некоторых обстоятельствах) менее читаемый:
att <- tapply(ToothGrowth$len, list(ToothGrowth$dose, ToothGrowth$supp), mean)
att
OJ VC
0.5 13.23 7.98
1 22.70 16.77
2 26.06 26.14
Есть еще раз, когда мы не можем использовать by
или tapply
И мы должны использовать aggregate
.
ag1 <- aggregate(cbind(Ozone, Temp) ~ Month, data = airquality, mean)
ag1
Month Ozone Temp
1 5 23.61538 66.73077
2 6 29.44444 78.22222
3 7 59.11538 83.88462
4 8 59.96154 83.96154
5 9 31.44828 76.89655
Мы не можем получить предыдущий результат с tapply
В одном вызове, но мы должны рассчитать среднее значение. Month
Для каждого элемента, а затем объединить их (также обратите внимание, что мы должны вызвать na.rm = TRUE
, поскольку formula
Методы aggregate
функция по умолчанию na.action = na.omit
):
ta1 <- tapply(airquality$Ozone, airquality$Month, mean, na.rm = TRUE)
ta2 <- tapply(airquality$Temp, airquality$Month, mean, na.rm = TRUE)
cbind(ta1, ta2)
ta1 ta2
5 23.61538 65.54839
6 29.44444 79.10000
7 59.11538 83.90323
8 59.96154 83.96774
9 31.44828 76.90000
пока с by
Мы просто не можем добиться этого, фактически следующий вызов функции возвращает ошибку (но, скорее всего, это связано с прилагаемой функцией, mean
):
by(airquality[c("Ozone", "Temp")], airquality$Month, mean, na.rm = TRUE)
В других случаях результаты одинаковы, и различия находятся только в классе (а затем, как это показано/распечатано, и не только - пример, как его подмножество):
byagg <- by(airquality[c("Ozone", "Temp")], airquality$Month, summary)
aggagg <- aggregate(cbind(Ozone, Temp) ~ Month, data = airquality, summary)
Предыдущий код достигает одной и той же цели и результатов, в некоторых точках, какой инструмент в использовании является лишь вопросом личных вкусов и потребностей; Предыдущие два объекта имеют очень разные потребности в условиях субстатинга.
Есть много отличных ответов, которые обсуждают различия в случаях использования для каждой функции. Ни один из ответов не обсуждает различия в производительности. Это разумно, потому что различные функции ожидают различных вводов и производят различные результаты, однако большинство из них имеют общую общую цель, чтобы оценить серии/группы. Мой ответ сосредоточится на производительности. Из -за вышеупомянутого создания ввода из векторов включено в время, а также apply
Функция не измеряется.
Я проверил две разные функции sum
и length
сразу. Проверка по объему составляет 50 м при входе и 50K на выходе. Я также включил два популярных пакета, которые не использовались в то время, когда был задан вопрос, data.table
и dplyr
. Анкет Оба определенно стоит посмотреть, если вы стремитесь к хорошей производительности.
library(dplyr)
library(data.table)
set.seed(123)
n = 5e7
k = 5e5
x = runif(n)
grp = sample(k, n, TRUE)
timing = list()
# sapply
timing[["sapply"]] = system.time({
lt = split(x, grp)
r.sapply = sapply(lt, function(x) list(sum(x), length(x)), simplify = FALSE)
})
# lapply
timing[["lapply"]] = system.time({
lt = split(x, grp)
r.lapply = lapply(lt, function(x) list(sum(x), length(x)))
})
# tapply
timing[["tapply"]] = system.time(
r.tapply <- tapply(x, list(grp), function(x) list(sum(x), length(x)))
)
# by
timing[["by"]] = system.time(
r.by <- by(x, list(grp), function(x) list(sum(x), length(x)), simplify = FALSE)
)
# aggregate
timing[["aggregate"]] = system.time(
r.aggregate <- aggregate(x, list(grp), function(x) list(sum(x), length(x)), simplify = FALSE)
)
# dplyr
timing[["dplyr"]] = system.time({
df = data_frame(x, grp)
r.dplyr = summarise(group_by(df, grp), sum(x), n())
})
# data.table
timing[["data.table"]] = system.time({
dt = setnames(setDT(list(x, grp)), c("x","grp"))
r.data.table = dt[, .(sum(x), .N), grp]
})
# all output size match to group count
sapply(list(sapply=r.sapply, lapply=r.lapply, tapply=r.tapply, by=r.by, aggregate=r.aggregate, dplyr=r.dplyr, data.table=r.data.table),
function(x) (if(is.data.frame(x)) nrow else length)(x)==k)
# sapply lapply tapply by aggregate dplyr data.table
# TRUE TRUE TRUE TRUE TRUE TRUE TRUE
# print timings
as.data.table(sapply(timing, `[[`, "elapsed"), keep.rownames = TRUE
)[,.(fun = V1, elapsed = V2)
][order(-elapsed)]
# fun elapsed
#1: aggregate 109.139
#2: by 25.738
#3: dplyr 18.978
#4: tapply 17.006
#5: lapply 11.524
#6: sapply 11.326
#7: data.table 2.686
Возможно, стоит упомянуть ave
. ave
является tapply
дружеский двоюродный брат. Он возвращает результаты в форме, которую вы можете подключить прямо в вашу рамку данных.
dfr <- data.frame(a=1:20, f=rep(LETTERS[1:5], each=4))
means <- tapply(dfr$a, dfr$f, mean)
## A B C D E
## 2.5 6.5 10.5 14.5 18.5
## great, but putting it back in the data frame is another line:
dfr$m <- means[dfr$f]
dfr$m2 <- ave(dfr$a, dfr$f, FUN=mean) # NB argument name FUN is needed!
dfr
## a f m m2
## 1 A 2.5 2.5
## 2 A 2.5 2.5
## 3 A 2.5 2.5
## 4 A 2.5 2.5
## 5 B 6.5 6.5
## 6 B 6.5 6.5
## 7 B 6.5 6.5
## ...
В базовом пакете нет ничего, что работает ave
для целых кадров данных (как by
как tapply
для кадров данных). Но вы можете толстить это:
dfr$foo <- ave(1:nrow(dfr), dfr$f, FUN=function(x) {
x <- dfr[x,]
sum(x$m*x$m2)
})
dfr
## a f m m2 foo
## 1 1 A 2.5 2.5 25
## 2 2 A 2.5 2.5 25
## 3 3 A 2.5 2.5 25
## ...
Несмотря на все отличные ответы здесь, есть еще 2 базовых функция, которые заслуживают упомянутых, полезные outer
функция и неясный eapply
функция
наружный
outer
очень полезная функция, скрытая как более мирская. Если вы прочитаете помощь для outer
Его описание говорит:
The outer product of the arrays X and Y is the array A with dimension
c(dim(X), dim(Y)) where element A[c(arrayindex.x, arrayindex.y)] =
FUN(X[arrayindex.x], Y[arrayindex.y], ...).
Что заставляет кажется, что это полезно только для линейных вещей типа алгебры. Однако это можно использовать так же, как mapply
Чтобы применить функцию к двум векторам входов. Разница в том, что mapply
применяет функцию к первым двум элементам, а затем ко вторым двум и т. Д., В то время как outer
Примените функцию для каждой комбинации одного элемента из первого вектора и один со второго. Например:
A<-c(1,3,5,7,9)
B<-c(0,3,6,9,12)
mapply(FUN=pmax, A, B)
> mapply(FUN=pmax, A, B)
[1] 1 3 6 9 12
outer(A,B, pmax)
> outer(A,B, pmax)
[,1] [,2] [,3] [,4] [,5]
[1,] 1 3 6 9 12
[2,] 3 3 6 9 12
[3,] 5 5 6 9 12
[4,] 7 7 7 9 12
[5,] 9 9 9 9 12
Я лично использовал это, когда у меня есть вектор ценностей и векторных условий, и хочу увидеть, какие значения соответствуют условиям.
посмотреть
eapply
как lapply
За исключением того, что вместо того, чтобы применять функцию к каждому элементу в списке, она применяет функцию к каждому элементу в среде. Например, если вы хотите найти список пользовательских функций в глобальной среде:
A<-c(1,3,5,7,9)
B<-c(0,3,6,9,12)
C<-list(x=1, y=2)
D<-function(x){x+1}
> eapply(.GlobalEnv, is.function)
$A
[1] FALSE
$B
[1] FALSE
$C
[1] FALSE
$D
[1] TRUE
Честно говоря, я не использую это очень много, но если вы строите много пакетов или создаете много сред, он может пригодиться.
Я недавно обнаружил довольно полезный sweep
функционируйте и добавьте его здесь ради полноты:
подметать
Основная идея заключается в подметать через строку массива или столбец и вернуть модифицированный массив. Примером сделает это понятно (источник: datacamp.):
Допустим, у вас есть матрица и хотите стандартизировать это в столбце:
dataPoints <- matrix(4:15, nrow = 4)
# Find means per column with `apply()`
dataPoints_means <- apply(dataPoints, 2, mean)
# Find standard deviation with `apply()`
dataPoints_sdev <- apply(dataPoints, 2, sd)
# Center the points
dataPoints_Trans1 <- sweep(dataPoints, 2, dataPoints_means,"-")
print(dataPoints_Trans1)
## [,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
# Return the result
dataPoints_Trans1
## [,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
# Normalize
dataPoints_Trans2 <- sweep(dataPoints_Trans1, 2, dataPoints_sdev, "/")
# Return the result
dataPoints_Trans2
## [,1] [,2] [,3]
## [1,] -1.1618950 -1.1618950 -1.1618950
## [2,] -0.3872983 -0.3872983 -0.3872983
## [3,] 0.3872983 0.3872983 0.3872983
## [4,] 1.1618950 1.1618950 1.1618950
NB: Для этого простого примера один и тот же результат может, конечно, можно достичь легче
apply(dataPoints, 2, scale)