Всякий раз, когда я хочу сделать что-то «сопоставить» py в R, я обычно пытаюсь использовать функцию в apply
семье.
Однако я никогда не понимал различий между ними - как { sapply
, lapply
и т. Д.} Применять функцию к входу / групповому вводу, как будет выглядеть вывод, или даже каким может быть ввод - поэтому я часто просто пройди их все, пока я не получу то, что хочу.
Может кто-нибудь объяснить, как использовать какой, когда?
Мое текущее (вероятно, неправильное / неполное) понимание ...
sapply(vec, f)
: вход является вектором. Выходной вектор / матрица, где элементi
являетсяf(vec[i])
, что дает вам матрицу , еслиf
имеет выход многоэлементногоlapply(vec, f)
: тоже самоеsapply
, но вывод есть список?apply(matrix, 1/2, f)
: вход является матрицей. output - вектор, где elementi
- это f (строка / столбец матрицы i)tapply(vector, grouping, f)
: Выход матрица / массив, в котором элемент в матрице / массиве значенияf
при группировкеg
вектора, иg
получает толкнул к / именам Col строкаby(dataframe, grouping, f)
: пустьg
будет группировка. применитьf
к каждому столбцу группы / dataframe. Довольно распечатать группировку и значениеf
в каждом столбце.aggregate(matrix, grouping, f)
: похоже наby
, но вместо того, чтобы красиво печатать вывод, агрегат вставляет все в информационный фрейм.
Дополнительный вопрос: я до сих пор не изучил plyr или не изменил форму - полностью plyr
или reshape
полностью я бы их заменил?
*apply()
иby
. Plyr (по крайней мере, мне) кажется гораздо более последовательным в том, что я всегда точно знаю, какой формат данных он ожидает, и что именно он будет выплевывать. Это избавляет меня от многих хлопот.doBy
и возможности выбора и примененияdata.table
.sapply
это простоlapply
с добавлениемsimplify2array
на выходе.apply
приводит к атомарному вектору, но вывод может быть вектором или списком.by
разбивает фреймы данных на суб-фреймы, но не используетf
отдельно столбцы. Только если есть метод для класса «data.frame», можноf
применять по столбцамby
.aggregate
является универсальным, поэтому существуют разные методы для разных классов первого аргумента.Ответы:
R имеет много * применяет функции, которые умело описаны в файлах справки (например
?apply
). Однако их достаточно, чтобы начинающим пользователям было трудно решить, какой из них подходит для их ситуации, или даже запомнить их все. У них может быть общее чувство, что «я должен использовать здесь функцию * apply», но поначалу бывает сложно держать их все прямо.Несмотря на тот факт (отмеченный в других ответах), что большая часть функциональности семейства * apply покрыта чрезвычайно популярным
plyr
пакетом, базовые функции остаются полезными и их стоит знать.Этот ответ призван служить своего рода указателем для новых пользователей, чтобы помочь им направить их к правильной функции * apply для их конкретной проблемы. Обратите внимание, это не предназначено просто для регургитации или замены документации R! Надежда состоит в том, что этот ответ поможет вам решить, какая * применимая функция подходит для вашей ситуации, а затем вам предстоит изучить ее дальше. За одним исключением, различия в производительности не будут устранены.
apply - применять, когда вы хотите применить функцию к строкам или столбцам матрицы (и многомерных аналогов); как правило, не рекомендуется для фреймов данных, так как он сначала приведёт к матрице.
Если вы хотите средства строк / столбцов или суммы для 2D - матрицы, убедитесь , что для расследования оптимизированный, молниеносный
colMeans
,rowMeans
,colSums
,rowSums
.lapply - когда вы хотите применить функцию к каждому элементу списка по очереди и получить список обратно.
Это рабочая лошадка многих других * применимых функций. Отогните их код, и вы часто найдете
lapply
под ним.sapply - когда вы хотите применить функцию к каждому элементу списка по очереди, но вы хотите вернуть вектор , а не список.
Если вы обнаружите, что печатаете
unlist(lapply(...))
, остановитесь и подумайтеsapply
.При более продвинутом использовании
sapply
он будет пытаться привести результат к многомерному массиву, если это необходимо. Например, если наша функция возвращает векторы одинаковой длины,sapply
будем использовать их в качестве столбцов матрицы:Если наша функция возвращает 2-мерную матрицу, она
sapply
будет делать то же самое, обрабатывая каждую возвращенную матрицу как один длинный вектор:Если мы не укажем
simplify = "array"
, в этом случае он будет использовать отдельные матрицы для построения многомерного массива:Каждое из этих поведений, конечно, зависит от нашей функции, возвращающей векторы или матрицы одинаковой длины или размера.
vapply - когда вы хотите использовать,
sapply
но, возможно, нужно выжать еще немного скорости из вашего кода.Для
vapply
, вы в основном даете R пример того , что такая вещи вашей функция будет возвращать, которая может сэкономить время принуждения возвращаемых значений , чтобы поместиться в одном атомном векторе.mapply - для случаев, когда у вас есть несколько структур данных (например, векторы, списки), и вы хотите применить функцию к первым элементам каждого, а затем ко вторым элементам каждого и т. д., приведя результат к вектору / массиву, как в
sapply
,Это многовариантно в том смысле, что ваша функция должна принимать несколько аргументов.
Map - Обертка для
mapply
withSIMPLIFY = FALSE
, поэтому она гарантированно вернет список.rapply - для случаев, когда вы хотите применить функцию к каждому элементу структуры вложенного списка , рекурсивно.
Чтобы дать вам некоторое представление о том, как необычно
rapply
, я забыл об этом, когда впервые опубликовал этот ответ! Очевидно, я уверен, что многие люди используют его, но YMMV.rapply
Лучше всего проиллюстрировать пользовательскую функцию для применения:tapply - если вы хотите применить функцию к подмножествам вектора, а подмножества определяются каким-то другим вектором, обычно фактором.
Черная овца семейства * применяет, родов. Использование в файле справки фразы «рваный массив» может быть немного запутанным , но на самом деле все довольно просто.
Вектор:
Фактор (одинаковой длины!), Определяющий группы:
Сложите значения в
x
каждой подгруппе, определенной какy
:Более сложные примеры могут быть обработаны, когда подгруппы определяются уникальными комбинациями списка из нескольких факторов.
tapply
аналогичен по духу сплит-применять функции-объединить , которые являются общими в R (aggregate
,by
,ave
,ddply
и т.д.) Следовательно , его статус черные овцы.источник
by
это чисто раздвоение иaggregate
лежитtapply
в их основе. Я думаю, что черная овца делает отличную ткань.aggregate
иby
так же? (Я, наконец, понимаю их после вашего описания!, Но они довольно распространены, поэтому может быть полезно выделить и привести несколько конкретных примеров для этих двух функций.)aggregate
,by
и т.д., на основе * применяются функции, как вы к ним , используя разные достаточно с точки зрения пользователей , что они должны быть представлены в виде отдельного ответа. Я могу попытаться сделать это, если у меня будет время, или, может быть, кто-то другой побьет меня и заработает мой голос.?Map
как родственникmapply
data.frame
s являются абсолютно центральной частью R и какlist
объект, которым часто манипулируют, вlapply
частности. Они также действуют как контейнеры для группировки векторов / факторов многих типов в традиционный прямоугольный набор данных. Хотяdata.table
иplyr
могут добавлять определенный тип синтаксиса, который некоторым может показаться более удобным, они расширяются и действуютdata.frame
соответственно на s.Кроме того, здесь показано, как различные
plyr
функции соответствуют базовым*apply
функциям (от вступления к документу plyr с веб-страницы plyr http://had.co.nz/plyr/ ).Одна из целей
plyr
состоит в том, чтобы обеспечить согласованные соглашения об именах для каждой из функций, кодируя входные и выходные типы данных в имени функции. Он также обеспечивает согласованность в выводе, поскольку выход изdlply()
него легко переноситсяldply()
для получения полезного вывода и т. Д.Концептуально обучение
plyr
не сложнее, чем понимание базовых*apply
функций.plyr
иreshape
функции заменили почти все эти функции в моем повседневном использовании. Но также из вступления к документу Plyr:источник
*apply()
семейство функций. Для меня этоddply()
было очень интуитивно понятно, так как я был знаком с функциями агрегации SQL.ddply()
стал моим молотом для решения многих проблем, некоторые из которых могли бы быть лучше решены с помощью других команд.plyr
функций, аналогична*apply
функциям, поэтому, если вы можете сделать одно, вы можете сделать другое, ноplyr
функции легче запомнить. Но я полностью согласен сddply()
молотком!join()
функцию, которая выполняет задачи, аналогичные слиянию. Возможно, более важно упомянуть об этом в контексте plyr.eapply
vapply
и недостаткиsapply
. Основным преимуществомvapply
является то, что он обеспечивает тип и длину вывода, поэтому вы получите либо точный ожидаемый результат, либо информативную ошибку. С другой стороны,sapply
мы попытаемся упростить вывод, следуя правилам, которые не всегда очевидны, и в противном случае вернемся к списку. Например, попытаться предсказать тип выхода этого будет производить:sapply(list(1:5, 6:10, matrix(1:4, 2)), function(x) head(x, 1))
. Как насчетsapply(list(matrix(1:4, 2), matrix(1:4, 2)), ...)
?Из слайда 21 http://www.slideshare.net/hadley/plyr-one-data-analytic-strategy :
(Надеюсь, это ясно, что
apply
соответствует @ Hadley'saaply
иaggregate
соответствует @ Hadley'sddply
и т. Д. Слайд 20 того же слайдшера прояснит, если вы не получите его из этого изображения.)(слева ввод, сверху вывод)
источник
Сначала начните с отличного ответа Джорана - сомнительно, что все может быть лучше.
Тогда следующая мнемоника может помочь вспомнить различия между каждым. В то время как некоторые из них очевидны, другие могут быть не так - для них вы найдете оправдание в обсуждениях Джорана.
мнемоника
lapply
является применением списка, которое действует на список или вектор и возвращает список.sapply
является простымlapply
(функция по умолчанию возвращает вектор или матрицу, когда это возможно)vapply
является проверенным применением (позволяет предварительно указать тип возвращаемого объекта)rapply
является рекурсивным применением для вложенных списков, то есть списков в спискахtapply
является тегом применить, где теги идентифицируют подмножестваapply
является универсальным : применяет функцию к строкам или столбцам матрицы (или, в более общем случае, к измерениям массива)Создание правильного фона
Если использование
apply
семьи все еще кажется вам чуждым, возможно, вам не хватает ключевой точки зрения.Эти две статьи могут помочь. Они обеспечивают необходимую основу для мотивации методов функционального программирования , предоставляемых
apply
семейством функций.Пользователи Lisp сразу узнают эту парадигму. Если вы не знакомы с Lisp, то, как только вы разберетесь с FP, вы получите мощную точку зрения для использования в R - и у вас
apply
будет гораздо больше смысла.источник
Так как я понял, что (очень отличные) ответы на этот пост отсутствуют
by
иaggregate
объяснения. Вот мой вклад.ПО
by
Функции, как указано в документации , может быть , хотя, как «обертки» дляtapply
. Силаby
возникает, когда мы хотим вычислить задачу, котораяtapply
не справляется. Одним из примеров является этот код:Если мы печатаем эти два объекта,
ct
иcb
мы «по существу» получаем одинаковые результаты, и единственные различия заключаются в том, как они отображаются, и в разныхclass
атрибутах соответственноby
дляcb
иarray
дляct
.Как я уже сказал, сила
by
возникает, когда мы не можем использоватьtapply
; следующий код является одним из примеров:R говорит, что аргументы должны иметь одинаковую длину, скажем, «мы хотим вычислить
summary
переменную all по всей длинеiris
фактораSpecies
»: но R просто не может этого сделать, потому что не знает, как с этим обращаться.С помощью
by
функции R отправьте конкретный метод дляdata frame
класса, а затем разрешитеsummary
функции работать, даже если длина первого аргумента (и типа тоже) различна.это действительно работает, и результат очень удивителен. Это объект класса,
by
который вместеSpecies
(скажем, для каждого из них) вычисляетsummary
каждую переменную.Обратите внимание, что если первый аргумент - это
data frame
, отправленная функция должна иметь метод для этого класса объектов. Например, если мы используем этот код сmean
функцией, у нас будет этот код, который вообще не имеет смысла:ОБЩИЙ
aggregate
может рассматриваться как другой способ использования,tapply
если мы используем его таким образом.Два непосредственных различия состоят в том, что второй аргумент
aggregate
должен быть списком, в то время какtapply
может (не обязательно) быть списком, и что выходныеaggregate
данные представляют собой фрейм данных, а одинtapply
- являетсяarray
.Сила в
aggregate
том, что он может легко обрабатывать подмножества данных сsubset
аргументом и что у него есть методы дляts
объектов,formula
а также.Эти элементы
aggregate
облегчают работу с этимtapply
в некоторых ситуациях. Вот несколько примеров (доступно в документации):Мы можем добиться того же самого,
tapply
но синтаксис немного сложнее, а вывод (в некоторых случаях) менее читабелен:Есть другие случаи, когда мы не можем использовать
by
илиtapply
и мы должны использоватьaggregate
.Мы не можем получить предыдущий результат с
tapply
одним вызовом, но мы должны вычислить среднее значениеMonth
для каждого элемента и затем объединить их (также обратите внимание, что мы должны вызватьna.rm = TRUE
, потому чтоformula
методыaggregate
функции по умолчанию имеютna.action = na.omit
):в то время как с помощью
by
мы просто не можем этого достичь, на самом деле следующий вызов функции возвращает ошибку (но, скорее всего, это связано с предоставленной функциейmean
):В других случаях результаты совпадают, и различия заключаются только в объекте класса (а затем в том, как он показан / напечатан, а не только в примере, например, как его установить):
Предыдущий код достиг той же цели и результатов, в какой-то момент, какой инструмент использовать, зависит только от личных вкусов и потребностей; предыдущие два объекта имеют очень разные потребности с точки зрения поднабора.
источник
data.frame(tapply(unlist(iris[,-5]),list(rep(iris[,5],ncol(iris[-5])),col(iris[-5])),summary))
это использование tapply. With the right splitting there is nothing you cant do with
tapply. The only thing is it returns a matrix. Please be careful by saying we cant use
tapply`Есть много отличных ответов, которые обсуждают различия в вариантах использования для каждой функции. Ни один из ответов не обсуждает различия в производительности. Это разумно, потому что различные функции ожидают различного ввода и производят различный вывод, но большинство из них имеют общую общую цель - оценивать по сериям / группам. Мой ответ будет сосредоточен на производительности. Из-за вышеизложенного создание ввода из векторов включено в синхронизацию, также
apply
функция не измеряется.Я протестировал две разные функции
sum
иlength
сразу. Протестированный объем составляет 50 М на входе и 50 К на выходе. Я также включил два популярных в настоящее время пакета, которые не были широко использованы в то время, когда задавался вопрос,data.table
иdplyr
. И то, и другое определенно стоит посмотреть, если вы стремитесь к хорошей производительности.источник
Несмотря на все замечательные ответы здесь, есть еще 2 базовые функции, которые заслуживают упоминания, полезная
outer
функция и скрытаяeapply
функциявнешний
outer
это очень полезная функция, скрытая как более приземленная. Если вы прочитали справку, дляouter
ее описания говорится:из-за этого кажется, что это полезно только для вещей типа линейной алгебры. Тем не менее, это может быть очень похоже
mapply
на применение функции к двум векторам входов. Разница в томmapply
, что функция будет применена к первым двум элементам, а затем ко вторым двум и т. Д., Тогдаouter
как функция будет применяться к каждой комбинации одного элемента из первого вектора и одного из второго. Например:Я лично использовал это, когда у меня есть вектор значений и вектор условий, и я хочу посмотреть, какие значения соответствуют каким условиям.
eapply
eapply
похоже наlapply
то, что вместо того, чтобы применять функцию к каждому элементу в списке, она применяет функцию к каждому элементу в среде. Например, если вы хотите найти список пользовательских функций в глобальной среде:Честно говоря, я не очень этим пользуюсь, но если вы создаете много пакетов или создаете много сред, это может пригодиться.
источник
Возможно, стоит упомянуть
ave
.ave
этоtapply
«S дружелюбный кузен. Он возвращает результаты в форме, которую вы можете подключить обратно в свой фрейм данных.Там нет ничего в базовом пакете , который работает как
ave
для целых кадров данных (как этоby
, какtapply
для кадров данных). Но вы можете обмануть это:источник
Недавно я обнаружил довольно полезную
sweep
функцию и добавил ее здесь для полноты картины:развертка
Основная идея заключается в том, чтобы подметать через row- массива или столбцы и возвращает модифицированный массив. Пример прояснит это (источник: datacamp ):
Допустим, у вас есть матрица и вы хотите стандартизировать ее по столбцам:
NB: для этого простого примера тот же результат, конечно, может быть достигнут легче
apply(dataPoints, 2, scale)
источник
sweep
это функция высшего порядка , как и все другие упомянутые здесь, напримерapply
,sapply
,lapply
так и тот же вопрос может быть задан вопрос о общепринятом ответ с более чем 1000 upvotes и примеры приведены в ней. Просто посмотрите на пример, приведенныйapply
там.sweep(matrix(1:6,nrow=2),2,7:9,list)
. Это обычно более эффективно, чемapply
потому, что тамapply
, где есть циклы,sweep
можно использовать векторизованные функции.В схлопывания пакете недавно выпущенный на CRAN, я попытался сжать большую часть общего применять функции в только 2 функции:
dapply
(Data-Apply) применяет функции к строкам или (по умолчанию) столбцам матриц и data.frames и (по умолчанию) возвращает объект того же типа и с теми же атрибутами (если результат каждого вычисления не является атомарным иdrop = TRUE
). Производительность сопоставима со значениямиlapply
для столбцов data.frame и примерно в 2 раза быстрее, чемapply
для строк или столбцов матрицы. Параллелизм доступен черезmclapply
(только для MAC).Синтаксис:
Примеры:
BY
является универсальным S3 для вычисления split-apply-Combine с вектором, матрицей и методом data.frame. Это значительно быстрее , чемtapply
,by
иaggregate
(также быстрее , чемplyr
на большие объемы данныхdplyr
быстрее , хотя).Синтаксис:
Примеры:
Списки группирующих переменных также могут быть предоставлены
g
.Говоря о производительности: главная цель коллапса - способствовать высокопроизводительному программированию на R и полностью выйти за рамки раздельного применения и объединения. Для этого пакет имеет полный набор C ++ на основе быстро общие функции:
fmean
,fmedian
,fmode
,fsum
,fprod
,fsd
,fvar
,fmin
,fmax
,ffirst
,flast
,fNobs
,fNdistinct
,fscale
,fbetween
,fwithin
,fHDbetween
,fHDwithin
,flag
,fdiff
иfgrowth
. Они выполняют групповые вычисления за один проход данных (т.е. без разделения и рекомбинации).Синтаксис:
Примеры:
В пакете виньетки я предоставляю ориентиры. Программирование с помощью быстрых функций значительно быстрее, чем программирование с использованием dplyr или data.table , особенно для небольших данных, но также и для больших данных.
источник