У меня есть датафрейм с несколькими столбцами. Для каждой строки в кадре данных я хочу вызвать функцию в строке, и для ввода функции используются несколько столбцов из этой строки. Например, допустим, у меня есть эти данные и этот testFunc, который принимает два аргумента:
> df <- data.frame(x=c(1,2), y=c(3,4), z=c(5,6))
> df
x y z
1 1 3 5
2 2 4 6
> testFunc <- function(a, b) a + b
Допустим, я хочу применить этот testFunc к столбцам x и z. Итак, для строки 1 я хочу 1 + 5, а для строки 2 я хочу 2 + 6. Есть ли способ сделать это без написания цикла for, может быть, с помощью семейства apply?
Я попробовал это:
> df[,c('x','z')]
x z
1 1 5
2 2 6
> lapply(df[,c('x','z')], testFunc)
Error in a + b : 'b' is missing
Но есть ошибки, есть идеи?
РЕДАКТИРОВАТЬ: фактическая функция, которую я хочу вызвать, это не простая сумма, но это power.t.test. Я использовал + B только для примера. Конечная цель - сделать что-то вроде этого (написано в псевдокоде):
df = data.frame(
delta=c(delta_values),
power=c(power_values),
sig.level=c(sig.level_values)
)
lapply(df, power.t.test(delta_from_each_row_of_df,
power_from_each_row_of_df,
sig.level_from_each_row_of_df
))
где результатом является вектор выходных данных для power.t.test для каждой строки df.
dplyr
способа.Ответы:
Вы можете применить
apply
к подмножеству исходных данных.или если ваша функция просто сумма, используйте векторизованную версию:
Если вы хотите использовать
testFunc
РЕДАКТИРОВАТЬ Чтобы получить доступ к столбцам по имени, а не по индексу, вы можете сделать что-то вроде этого:
источник
apply
на больших data.frames, он скопирует весь объект (для преобразования в матрицу). Это также вызовет проблемы, если у вас есть различные объекты класса в data.frame.data.frame
Этоlist
, так что ...Для векторизованных функций
do.call
обычно хорошая ставка. Но имена аргументов вступают в игру. Здесь вашtestFunc
вызывается с аргументами x и y вместо a и b. Параметр...
позволяет передавать нерелевантные аргументы, не вызывая ошибки:Для не-векторных функций ,
mapply
будет работать, но вы должны соответствовать упорядочиванию арга или явно назвать их:Иногда
apply
будет работать - например, когда все аргументы имеют одинаковый тип, поэтому приведениеdata.frame
к матрице не вызывает проблем при изменении типов данных. Ваш пример был такого рода.Если ваша функция должна вызываться в другой функции, в которую передаются все аргументы, существует гораздо более приятный метод, чем этот. Изучите первые строки тела,
lm()
если вы хотите пойти по этому пути.источник
Vectorize
в качестве оболочкиmapply
для векторизации функцийиспользование
mapply
источник
Новый ответ с
dplyr
пакетомЕсли функция, которую вы хотите применить, векторизована, то вы можете использовать
mutate
функцию изdplyr
пакета:Старый ответ с
plyr
пакетомПо моему скромному мнению, инструмент, который лучше всего подходит для этой задачи, взят
mdply
изplyr
пакета.Пример:
К сожалению, как отметил Бертжан Бруксема , этот подход не работает, если вы не используете все столбцы фрейма данных в
mdply
вызове. Например,источник
dplyr::mutate_each
. Например:iris %>% mutate_each(funs(half = . / 2),-Species)
.Другие правильно указали, что
mapply
сделано для этой цели, но (для полноты картины) концептуально более простым методом является просто использованиеfor
цикла.источник
Многие функции уже векторизованы, и поэтому нет необходимости в каких-либо итерациях (ни
for
циклах, ни*pply
функциях). ВыtestFunc
один из таких примеров. Вы можете просто позвонить:В общем, я бы рекомендовал сначала попробовать такие подходы к векторизации и посмотреть, принесут ли они вам ожидаемые результаты.
В качестве альтернативы, если вам нужно передать несколько аргументов в функцию, которая не является векторизованной,
mapply
может быть то, что вы ищете:источник
Вот альтернативный подход. Это более интуитивно понятно.
Я считаю, что один из ключевых аспектов, который я не учел в некоторых ответах, на которые я обращаю внимание в потомках, - apply () позволяет легко выполнять вычисления строк, но только для матричных (все числовые) данных.
операции над столбцами возможны еще для датафреймов:
Чтобы оперировать строками, мы сначала делаем транспонирование.
Недостатком является то, что я верю, что R сделает копию вашей таблицы данных. Что может быть проблемой памяти. (Это действительно грустно, потому что программно просто для tdf просто быть итератором исходного df, тем самым экономя память, но R не допускает ссылки на указатель или итератор.)
Кроме того, связанный вопрос, как работать с каждой отдельной ячейкой в кадре данных.
источник
Я пришел сюда в поисках названия функции tidyverse, которое, как я знал, существовало. Добавление этого для (моей) будущей ссылки и для
tidyverse
энтузиастов:purrrlyr:invoke_rows
(purrr:invoke_rows
в более старых версиях).С подключением к стандартным методам статистики, как в первоначальном вопросе, пакет метлы , вероятно, поможет.
источник
@ user20877984 ответ отличный. Так как они суммировали это намного лучше, чем мой предыдущий ответ, вот моя (возможно, все еще дрянная) попытка применения концепции:
Используя
do.call
в основном:Работа над полным набором данных:
lapply
power.t.test
функции к каждому из рядов заданных значений:источник
2
, а не просто применяете поверх1
?data.table
имеет действительно интуитивный способ сделать это::=
Оператор может быть вызван в скобках , чтобы добавить новый столбец , используя функциюТакже легко принять константы в качестве аргументов, используя этот метод:
источник
Если столбцы data.frame имеют разные типы,
apply()
возникает проблема. Тонкость итераций строки заключается в том, какapply(a.data.frame, 1, ...)
происходит неявное преобразование типов в символьные типы, когда столбцы имеют разные типы; например. коэффициент и числовой столбец. Вот пример использования коэффициента в одном столбце для изменения числового столбца:Вычитание не выполняется, поскольку столбцы преобразуются в типы символов.
Одним из исправлений является обратное преобразование второго столбца в число:
Но преобразований можно избежать, если разделить столбцы и использовать
mapply()
:mapply()
необходим, потому[[ ]]
что не принимает векторный аргумент. Таким образом, итерация столбца может быть выполнена до вычитания путем передачи вектора в[]
немного более уродливый код:источник
Действительно хорошая функция для этого
adply
изplyr
, особенно если вы хотите , чтобы добавить результат к исходному dataframe. Эта функция и ее двоюродный братddply
избавили меня от многих головных болей и строк кода!Кроме того, вы можете вызвать функцию, которую вы хотите.
источник