Чтобы поделиться еще несколькими советами и приемами для R , какая ваша самая полезная функция или прием? Умная векторизация? Ввод / вывод данных? Визуализация и графика? Статистический анализ? Специальные функции? Сама интерактивная среда?
По одному пункту на публикацию, и мы увидим победителя с помощью голосов.
[Править 25 августа 2008 г.]: Итак, через неделю, кажется, что простой str()победил в опросе. Поскольку я сам люблю рекомендовать это, это простой ответ.
@ars: это вопрос, на который нет однозначного ответа . Ergo сделай это CW.
dmckee --- котенок экс-модератора
2
@JD Длинный веселый комментарий. к сожалению, он был спрятан за складкой. Я имею в виду, что отвечать на сложные вопросы R на самом деле не выгодно. Так что для меня нормально, если парни, которые задают красивые вопросы, которые делают R на карте, наконец, получат некоторую заслугу. Кроме того, это, безусловно, более полезно для пользователей R, чем ваш любимый вопрос о C-трюке для программистов на C ...
Может быть очень полезно размещать легко воспроизводимые фрагменты данных, когда вы просите о помощи, или редактировать или изменять порядок уровней фактора.
head () и tail (), чтобы получить первую и последнюю части фрейма данных, вектора, матрицы, функции и т. д. Это быстрый способ проверить правильность загрузки, особенно с большими фреймами данных.
Одна приятная функция: для чтения данных используются соединения, которые могут быть локальными файлами, удаленными файлами, доступными через http, каналами из других программ и т. Д.
В качестве простого примера рассмотрим этот доступ для N = 10 случайных целых чисел от min = 100 до max = 200 с сайта random.org (который предоставляет истинные случайные числа, основанные на атмосферном шуме, а не на генераторе псевдослучайных чисел):
R> site <- "http://random.org/integers/"# base URL
R> query <- "num=10&min=100&max=200&col=2&base=10&format=plain&rnd=new"
R> txt <- paste(site, query, sep="?") # concat url and query string
R> nums <- read.table(file=txt) # and read the data
R> nums # and show it
V1 V2
11651432107118310313241911005138185
R>
Кроме того, пакет random предоставляет несколько удобных функций для доступа к random.org .
BTW-- Я хотел бы предложить , что вы должны сделать selfanswers CW , если (1) вы разместите их в кратчайшие сроки и (2) вы не делаете вопрос CW. В противном случае это выглядит так, как будто вы пытаетесь обмануть систему повторений. YMMV и все такое.
dmckee --- котенок экс-модератора
1
Это не игра в систему, это просто начало работы. Он все еще волен принять любой другой ответ.
ars
2
@ars: Он может принять это. Я также не буду пытаться заставить его использовать вики, если он не прислушается к моему совету. Но я не буду публиковать заранее подготовленный ответ, не отметив его как вики, и не буду голосовать за него без него. Принимайте это как следует.
dmckee --- котенок экс-модератора
4
@Dirk: вполне приемлемо, даже если Джефф и Джоэл поощряют его, отвечать на свой вопрос. Нет НИКАКОГО требования, даже неофициального, давать ответ CW. Вы явно не играете в систему. Еще раз, просто игнорируйте вики-полицию сообщества.
Juliet
8
Я должен согласиться с тем, что частично цель сайтов - предоставить лучшие ответы на общие проблемы и общий ресурс. Задавая вопросы и давая хороший ответ, можно укрепить тему. Это особенно полезно с новыми / маленькими тегами, такими как R.
kpierce8
35
Я нахожу , что я использую with()и все within()больше и больше. Больше $не надо засорять мой код, и не нужно начинать прикреплять объекты к пути поиска. А если серьезно, я считаю, что и with()т. Д. Делают мои сценарии анализа данных более ясными.
> df <- data.frame(A = runif(10), B = rnorm(10))
> A <- 1:10## something else hanging around...
> with(df, A + B) ## I know this will use A in df!
[1] 0.04334784 -0.404446861.993688160.13871605 -1.17734837
[6] 0.424738122.330142261.616907991.419018600.8699079
with()устанавливает среду, в которой оценивается выражение R. within()делает то же самое, но позволяет вам изменять объект данных, используемый для создания среды.
> df <- within(df, C <- rpois(10, lambda = 2))
> head(df)
A B C
10.62635571 -0.5830079120.04810539 -0.4525522130.397069791.5966184340.95802501 -0.8193090250.76772541 -1.9450738260.213350060.21138814
Когда я впервые использовал within()это, я не осознавал, что вам нужно выполнить присваивание как часть оцениваемого выражения и присвоить возвращаемый объект (как указано выше), чтобы получить желаемый эффект.
Я обнаружил, что электронные таблицы Google - отличный способ для всех соавторов быть на одной странице. Кроме того, Google Forms позволяет собирать данные от респондентов и легко записывать их в электронную таблицу Google. Поскольку данные часто меняются и почти никогда не бывают окончательными, для R гораздо предпочтительнее читать электронную таблицу Google напрямую, чем загружать файлы CSV и считывать их.
# Get data from google spreadsheetlibrary(RGoogleDocs)
ps <-readline(prompt="get the password in ")
auth = getGoogleAuth("me@gmail.com", ps, service="wise")
sheets.con <- getGoogleDocsConnection(auth)
ts2=getWorksheets("Data Collection Repos",sheets.con)
names(ts2)
init.consent <-sheetAsMatrix(ts2$Sheet1,header=TRUE, as.data.frame=TRUE, trim=TRUE)
Я не могу вспомнить, какая из следующих команд, кроме одной или двух, занимает несколько секунд.
[Edit] Дирк спрашивает, зачем давать неверные имена? Я не знаю! Но на практике я, конечно, довольно часто сталкиваюсь с этой проблемой. Например, используя пакет hashape reshape:
> library(reshape)
> df$z <- c(1,1,2,2,2)
> recast(df,z~.,id.var="z")
Aggregation requires fun.aggregate: length used as default
z (all)
114226
> recast(df,z~.,id.var="z")$(all)
Error: unexpected '('in"recast(df,z~.,id.var="z")$("
> recast(df,z~.,id.var="z")$`(all)`
Aggregation requires fun.aggregate: length used as default
[1] 46
Самое приятное то, что если вы делаете что-то, что на самом деле требует значительного количества времени, вы можете переключиться с %do%на %dopar%(с соответствующей серверной библиотекой) для мгновенного распараллеливания, даже в кластере. Очень красиво.
Я занимаюсь основными манипуляциями с данными, поэтому вот две встроенные функции ( преобразование , подмножество ) и одна библиотека ( sqldf ), которые я использую ежедневно.
создать образец данных о продажах
sales <- expand.grid(country = c('USA', 'UK', 'FR'),
product = c(1, 2, 3))
sales$revenue <- rnorm(dim(sales)[1], mean=100, sd=10)
> sales
country product revenue
1 USA 1108.459652 UK 197.079813 FR 199.662254 USA 2100.347545 UK 287.122626 FR 2112.860847 USA 395.878808 UK 396.435819 FR 394.59259
используйте transform (), чтобы добавить столбец
## transform currency to euros
usd2eur <- 1.434
transform(sales, euro = revenue * usd2eur)
>
country product revenue euro
1 USA 1108.45965155.53112 UK 197.07981139.21253 FR 199.66225142.9157...
используйте sqldf () для нарезки и агрегирования с SQL
Пакет sqldf предоставляет интерфейс SQL для фреймов данных R
## recast the previous subset() expression in SQL
sqldf('SELECT product, revenue FROM sales \
WHERE country = "USA" \
AND product IN (1,2)')
>
product revenue
11108.459722100.3475
Выполните агрегирование или GROUP BY
sqldf('select country, sum(revenue) revenue \
FROM sales \
GROUP BY country')
>
country revenue
1 FR 307.11572 UK 280.63823 USA 304.6860
Для более сложных функций map-reduce для фреймов данных ознакомьтесь с пакетом plyr . И если найти себе желание вытащить свои волосы, я рекомендую проверить Манипулирование данными с R .
Подмножества 'x []' усредняются, причем каждое подмножество состоит из наблюдений с одинаковыми уровнями факторов. Использование: ave (x, ..., FUN = mean)
Здесь есть небольшая ловушка, которая меня все время ловила. Если df $ column1 содержит значения NA, при подмножестве с использованием == будут извлечены любые значения, равные x, и любые NA. Чтобы этого избежать, используйте «% в%» вместо «==».
Мэтт Паркер,
Мэтт, ты абсолютно прав, и я ненавижу это, но мне нравится твой метод. Я обычно проверяю столбец на наличие НП, а затем удаляю их с помощью быстрой функции, которую я сделал, которая берет столбец фрейма данных и возвращает фрейм данных минус строки с НП только в этом столбце.
Дэн
по сути, я сокращаю фрейм данных до столбцов, в которых мне нужны значения, затем использую na.omit для получения правильных строк, а затем подмножество исходного набора данных только с этими строками. Простое использование na.omit удалит любую строку с любым NA, хотя я могу ошибаться.
Дэн
16
Иногда требуется rbindнесколько фреймов данных. do.call()позволит вам это сделать (кто-то должен был объяснить это мне, когда я задал этот вопрос при связывании, поскольку его использование не является очевидным).
Хорошее решение: я считаю, что это часто проще, чем использовать unsplit.
Ричи Коттон
16
В R программировании (не интерактивные сеансы), я использую if (bad.condition) stop("message")в много . Каждая функция начинается с нескольких из них, и, работая над вычислениями, я тоже добавляю их. Полагаю, я привык к использованию assert()в C. Преимущества двоякие. Во-первых, с этими проверками намного быстрее получить рабочий код. Во-вторых, что, вероятно, более важно, работать с существующим кодом намного проще, если вы видите эти проверки на каждом экране в редакторе. Вам не придется задаваться вопросом x>0, или доверять комментарию о том, что это ... вы узнаете с первого взгляда, что это так.
Неплохая привычка, и R предлагает еще один способ: stopfifnot(!bad.condition)более лаконичный.
Dirk Eddelbuettel 05
13
Эта traceback()функция необходима, когда у вас где-то есть ошибка, и вы не можете ее сразу понять. Он напечатает трассировку стека, что очень полезно, поскольку R по умолчанию не очень подробный.
Затем настройка options(error=recover)позволит вам «войти» в функцию, вызывающую ошибку, и попытаться понять, что именно происходит, как если бы вы полностью контролировали это и могли бы указать browser()в нем.
Эти три функции действительно могут помочь отладить ваш код.
options(error=recover)это мой любимый метод отладки.
Джошуа Ульрих,
12
Я действительно удивлен, что никто не написал о apply, tapply, lapply и sapply. Общее правило, которое я использую при работе с R, заключается в том, что если у меня есть цикл for, который выполняет обработку данных или моделирование, я пытаюсь выделить его и заменить на * apply. Некоторые люди уклоняются от функций * apply, потому что они думают, что можно передавать только функции с одним параметром. Ничего не может быть дальше от истины! Подобно передаче функций с параметрами в качестве объектов первого класса в Javascript, вы делаете это в R с анонимными функциями. Например:
> sapply(rnorm(100, 0, 1), round)
[1] 11011 -1 -2022 -2 -101 -101 -10 -100000
[26] 20 -1 -2001 -1151 -1011120 -11 -110 -11
[51] 211 -2 -10 -12 -11 -11 -10 -1 -2110 -1 -11120
[76] 000 -2 -111 -21 -1111000 -1 -30 -100011
> sapply(rnorm(100, 0, 1), round(x, 2)) # How can we pass a parameter?
Error in match.fun(FUN) : object 'x' not found
# Wrap your function call in an anonymous function to use parameters
> sapply(rnorm(100, 0, 1), function(x) {round(x, 2)})
[1] -0.05 -1.74 -0.09 -1.230.69 -1.430.760.550.96 -0.47 -0.81 -0.47
[13] 0.270.320.47 -1.28 -1.44 -1.930.51 -0.82 -0.06 -1.411.23 -0.26
[25] 0.22 -0.04 -2.170.60 -0.10 -0.920.132.621.03 -1.33 -1.73 -0.08
[37] 0.45 -0.930.400.051.09 -1.23 -0.350.620.01 -1.081.70 -1.27
[49] 0.550.60 -1.461.08 -1.88 -0.150.210.060.53 -1.16 -2.13 -0.03
[61] 0.33 -1.070.980.62 -0.01 -0.53 -1.17 -0.28 -0.950.71 -0.58 -0.03
[73] -1.47 -0.75 -0.540.42 -1.630.05 -1.900.40 -0.010.14 -1.581.37
[85] -1.00 -0.901.69 -0.11 -2.19 -0.741.34 -0.75 -0.51 -0.99 -0.36 -1.63
[97] -0.980.611.010.55# Note that anonymous functions aren't being called, but being passed.
> function() {print('hello #rstats')}()
function() {print('hello #rstats')}()
> a = function() {print('hello #rstats')}
> a
function() {print('hello #rstats')}
> a()
[1] "hello #rstats"
(Для тех, кто следит за #rstats, я также разместил это там).
Помните, используйте apply, sapply, lapply, tapply и do.call! Воспользуйтесь векторизацией R. Вы никогда не должны подходить к кучке кода R и видеть:
N = 10000
l = numeric()
for (i in seq(1:N)) {
sim <- rnorm(1, 0, 1)
l <- rbind(l, sim)
}
Мало того, что это не векторизовано, но и структура массива в R не увеличивается, как в Python (удвоение размера, когда пространство заканчивается, IIRC). Таким образом, каждый шаг rbind должен сначала вырасти l настолько, чтобы принять результаты от rbind (), а затем скопировать все содержимое предыдущего l. Ради интереса попробуйте описанное выше в R. Обратите внимание, сколько времени это займет (вам даже не понадобится Rprof или какая-либо функция синхронизации). Тогда попробуй
N=10000
l <- rnorm(N, 0, 1)
Лучше, чем первая версия:
N = 10000
l = numeric(N)
for (i in seq(1:N)) {
sim <- rnorm(1, 0, 1)
l[i] <- sim
}
apply, sapply, lapply и tapply полезны. Если вы хотите передать параметры именованной функции, например round, вы можете просто передать их вместе с apply вместо написания анонимной функции. Попробуйте «sapply (rnorm (10, 0, 1), round, digits = 2)», который выводит «[1] -0,29 0,29 1,31 -0,06 -1,90 -0,84 0,21 0,02 0,23 -1,10».
Daniel
11
По совету Дирка выкладываю единичные примеры. Я надеюсь, что они не слишком "милые" [умные, но мне все равно] или тривиальные для этой аудитории.
Линейные модели - это хлеб с маслом R. Когда число независимых переменных велико, у каждого есть два варианта. Во-первых, он использует lm.fit (), который получает матрицу проектирования x и ответ y в качестве аргументов, аналогично Matlab. Недостатком этого подхода является то, что возвращаемое значение представляет собой список объектов (подогнанные коэффициенты, остатки и т. Д.), А не объект класса «lm», который можно красиво резюмировать, использовать для прогнозирования, пошагового выбора и т. Д. Второе подход заключается в создании формулы:
> A
X1 X2 X3 X4 y
10.968523630.338271070.2613322570.628170211.642532620.080127550.691598280.0879941580.937804810.980130430.101675450.381193040.8652098320.165016620.483087340.066994580.417564150.2580716160.340277750.7508766...
> (f=paste("y ~",paste(names(A)[1:4],collapse=" + ")))
[1] "y ~ X1 + X2 + X3 + X4"
> lm(formula(f),data=A)
Call:
lm(formula = formula(f), data = A)
Coefficients:
(Intercept) X1 X2 X3 X4
0.782360.95406 -0.06738 -0.43686 -0.06644
Как насчет того, чтобы выбрать по одному для каждого сообщения и проиллюстрировать его примером? Затем мы можем продолжать работать несколько дней подряд и публиковать новые примеры с новыми командами ... [BTW: Насколько я помню, вам понадобится as.formula (paste (...)) для использования формулы. ]
Дирк Эддельбюттель
Вам не нужно явно создавать формулу для покрытия всех столбцов, так как форма «y ~. - 1» покрывает это. Знак "." означает «все столбцы, кроме зависимой переменной, а« - 1 »исключает константу, как в вашем примере.
Дирк Эддельбюттель,
Это верно для этого конкретного примера, но для X с ncols >> nrows я часто удаляю некоторые независимые переменные, особенно на заключительных этапах анализа. В этом случае по-прежнему удобно создавать формулу из имен фреймов данных.
gappy
10
Вы можете присвоить значение, возвращаемое из блока if-else.
Вместо, например,
condition <- runif(1) > 0.5if(condition) x <- 1else x <- 2
Вы также можете сделать это как x <- ifelse (condition, 1, 2), и в этом случае каждый компонент векторизуется.
Шейн
Шейн, вы могли бы, но если вы не очень глубоко разбираетесь в том, что делает ifelse (), вам, вероятно, не стоит! Это легко неправильно понять ...
Харлан,
Что в этом волшебного? Именно так if-then-elseвыражения работают на любом функциональном языке (не путать с if-then-elseоператорами ). Очень похоже на тернарный ?:оператор C-подобных языков.
Фрэнк
10
Как полный новичок в R и новичок в статистике, я люблю unclass()
печатать все элементы фрейма данных как обычный список.
Очень удобно просматривать полный набор данных за один раз, чтобы быстро выявить любые потенциальные проблемы.
CrossTable()из gmodelsпакета обеспечивает легкий доступ к кросс-таблицам в стиле SAS и SPSS, а также к обычным тестам (Chisq, McNemar и т. д.). По сути, это xtabs()навороченный вывод и некоторые дополнительные тесты, но он упрощает обмен выводами с язычниками.
Ницца!! Я довольно часто использую гмодели, но пропустил этот
Абхиджит
Хороший ответ, все, что может удержать меня от чрезмерного объяснения таблиц с язычниками, - это хорошее использование времени.
Stedy
7
Определенно system(). Возможность иметь доступ ко всем инструментам unix (по крайней мере, под Linux / MacOSX) из среды R быстро стала бесценной в моем повседневном рабочем процессе.
Это связано с моим предыдущим комментарием о соединениях: вы также можете использовать pipe () для передачи данных из команд Unix или в них. См. help(connections)Подробности и примеры.
Дирк Эддельбюттель,
6
Вот неприятный обходной путь для преобразования коэффициента в числовой. (Аналогично и для других типов данных)
Возможно, вы имели в виду вектор «в персонажа». В этом случае "as.character (old.var)" проще.
Дирк Эддельбюттель
1
Я всегда считал этот совет (который можно прочесть с коэффициентом?) Ошибочным. Вы должны быть уверены, что old.var является фактором, и это будет зависеть от параметров, которые вы установили для сеанса R. Использование as.numeric (as.character (old.var)) безопаснее и чище.
Эдуардо Леони
На самом деле не стоит отрицательного голоса, но все равно. У меня это работает.
Райан Р. Росарио
Райан - Не могли бы вы исправить свой код? Если old.var <- коэффициент (1: 2); ваш код даст [1] «1» «2» (не числовой.) возможно, вы имели в виду as.numeric (levels (old.var) [old.var])?
Эдуардо Леони
3
Или чуть более эффективно:as.numeric(levels(old.var))[old.var]
hadley
6
Хотя этот вопрос поднимался некоторое время, я недавно обнаружил в блоге SAS и R отличный трюк для использования этой команды cut. Команда используется для разделения данных на категории, и я буду использовать набор данных iris в качестве примера и разделить его на 10 категорий:
Еще одна уловка. Некоторые пакеты, как glmnet, только взять в качестве входов матрицы дизайна и переменный отклик. Если кто-то хочет подогнать модель со всеми взаимодействиями между элементами, он не может использовать формулу «y ~. ^ 2». Использование expand.grid()позволяет нам использовать мощные возможности индексирования массивов и векторных операций R.
Если функция моделирования не принимает формулу (что бывает очень редко!), Не лучше ли построить матрицу дизайна с помощью model.matrix?
Хэдли
Хороший. Я не знал о существовании этой функции. Вышеупомянутая функция эквивалентна model.matrix (~. ^ 2 -1, X) Но что касается передачи матриц, помимо glmnet, я часто передаю указатели на массивы пользовательским функциям C. В самом деле, я бы не знал, как передать формулу функции. У вас есть игрушечный пример?
gappy
5
Один из моих любимых, если не сказать несколько неортодоксальных приемов - это использование eval()и parse(). Этот пример, возможно, показывает, как это может быть полезно
Ситуации такого типа возникают чаще, и их использование eval()и parse()может помочь в их решении. Конечно, я приветствую любые отзывы об альтернативных способах написания кода.
Это также можно сделать с помощью именованных векторных элементов.
Дирк Эддельбюттель,
3
library (fortunes); fortune (106) Если ответ - parse (), вы обычно должны переосмыслить вопрос. - Thomas Lumley R-help (февраль 2005 г.)
Эдуардо Леони
Вот пример, в котором могут быть полезны eval () и parse (). Это включает в себя пакет Bioconductor, например hgu133a.db, и где вы пытаетесь получить различную информацию об идентификаторе набора зондов. Например: параметр библиотеки (hgu133a.db) <- 'SYMBOL' mget ('202431_s_at', env = eval (parse (text = paste ('hgu133a', parameter, sep = '')))) параметр <- 'ENTREZID 'mget (' 202431_s_at ', env = eval (parse (text = paste (' hgu133a ', parameter, sep =' '))))
andrewj
Как говорит Дирк, это лучше делать с помощью именованных векторных элементов или `get (paste (state, parameter, sep = '.'))`
Хэдли
@ Хэдли, не знала, что таким образом можно использовать get (). Спасибо.
andrewj
5
set.seed() устанавливает состояние генератора случайных чисел.
for (f в файлах) {if (! (f == 'mysource.r')) {print (paste ('Sourcing', f)) source (paste (d, f, sep = ''))}}
Я использую приведенный выше код для получения всех файлов в каталоге при запуске с различными служебными программами, которые я использую в моем интерактивном сеансе с R. Я уверен, что есть лучшие способы, но я считаю его полезным для своей работы. Строка, которая делает это, выглядит следующим образом.
Спасибо. Я просматривал пару веток на roxygen, и мне кажется, что я, вероятно, нахожусь на том уровне, на котором я должен попробовать написать простой пакет для самостоятельного использования.
mcheema
3
Для выполнения операции с рядом переменных в кадре данных. Это украдено из subset.data.frame.
get.vars<-function(vars,data){
nl <- as.list(1L:ncol(data))
names(nl) <- names(data)
vars <- eval(substitute(vars), nl, parent.frame())
data[,vars]
#do stuff here
}
get.vars(c(cyl:hwy,class),mpg)
Поначалу это кажется крутым, но в конечном итоге такой код доставит вам немало проблем. Всегда лучше быть откровенным.
Хэдли
хм, в последнее время я довольно часто использую этот трюк. Не могли бы вы подробнее рассказать о его безграничной проблеме?
Ian Fellows
Может быть, Хадли предлагает вместо этого использовать пакет plyr?
Кристофер Дюбуа,
3
Нет, это не завуалированное предложение использовать вместо этого plyr. Основная проблема вашего кода в том, что он семантически ленив - вместо того, чтобы заставлять пользователя явно объяснять то, что он хочет, вы делаете некую «магию», чтобы угадать. Проблема в том, что это делает функцию очень сложной для программирования - т.е. трудно написать функцию, которая вызывает, get.varsне перепрыгивая через множество обручей.
Хэдли
3
Я уже публиковал это однажды, но я так часто им пользуюсь, что подумал, что выложу еще раз. Это всего лишь небольшая функция, возвращающая имена и номера позиций data.frame. В этом нет ничего особенного, чтобы быть уверенным, но я почти никогда не прохожу через сеанс, не используя его несколько раз.
##creates an object from a data.frame listing the column names and location
Ответы:
str()
сообщает вам структуру любого объекта.источник
dir()
- имеет больше смысла.str
это тоже сокращение отstring
многих языков.class()
? Кажется, выявляет подобную информацию. Почему есть две такие похожие команды?class()
- это лишь малая частьstr()
отображаемой информацииОдна очень полезная функция, которую я часто использую, - это dput (), которая позволяет вам выгружать объект в виде кода R.
# Use the iris data set R> data(iris) # dput of a numeric vector R> dput(iris$Petal.Length) c(1.4, 1.4, 1.3, 1.5, 1.4, 1.7, 1.4, 1.5, 1.4, 1.5, 1.5, 1.6, 1.4, 1.1, 1.2, 1.5, 1.3, 1.4, 1.7, 1.5, 1.7, 1.5, 1, 1.7, 1.9, 1.6, 1.6, 1.5, 1.4, 1.6, 1.6, 1.5, 1.5, 1.4, 1.5, 1.2, 1.3, 1.4, 1.3, 1.5, 1.3, 1.3, 1.3, 1.6, 1.9, 1.4, 1.6, 1.4, 1.5, 1.4, 4.7, 4.5, 4.9, 4, 4.6, 4.5, 4.7, 3.3, 4.6, 3.9, 3.5, 4.2, 4, 4.7, 3.6, 4.4, 4.5, 4.1, 4.5, 3.9, 4.8, 4, 4.9, 4.7, 4.3, 4.4, 4.8, 5, 4.5, 3.5, 3.8, 3.7, 3.9, 5.1, 4.5, 4.5, 4.7, 4.4, 4.1, 4, 4.4, 4.6, 4, 3.3, 4.2, 4.2, 4.2, 4.3, 3, 4.1, 6, 5.1, 5.9, 5.6, 5.8, 6.6, 4.5, 6.3, 5.8, 6.1, 5.1, 5.3, 5.5, 5, 5.1, 5.3, 5.5, 6.7, 6.9, 5, 5.7, 4.9, 6.7, 4.9, 5.7, 6, 4.8, 4.9, 5.6, 5.8, 6.1, 6.4, 5.6, 5.1, 5.6, 6.1, 5.6, 5.5, 4.8, 5.4, 5.6, 5.1, 5.1, 5.9, 5.7, 5.2, 5, 5.2, 5.4, 5.1) # dput of a factor levels R> dput(levels(iris$Species)) c("setosa", "versicolor", "virginica")
Может быть очень полезно размещать легко воспроизводимые фрагменты данных, когда вы просите о помощи, или редактировать или изменять порядок уровней фактора.
источник
head () и tail (), чтобы получить первую и последнюю части фрейма данных, вектора, матрицы, функции и т. д. Это быстрый способ проверить правильность загрузки, особенно с большими фреймами данных.
источник
Одна приятная функция: для чтения данных используются соединения, которые могут быть локальными файлами, удаленными файлами, доступными через http, каналами из других программ и т. Д.
В качестве простого примера рассмотрим этот доступ для N = 10 случайных целых чисел от min = 100 до max = 200 с сайта random.org (который предоставляет истинные случайные числа, основанные на атмосферном шуме, а не на генераторе псевдослучайных чисел):
R> site <- "http://random.org/integers/" # base URL R> query <- "num=10&min=100&max=200&col=2&base=10&format=plain&rnd=new" R> txt <- paste(site, query, sep="?") # concat url and query string R> nums <- read.table(file=txt) # and read the data R> nums # and show it V1 V2 1 165 143 2 107 118 3 103 132 4 191 100 5 138 185 R>
Кроме того, пакет random предоставляет несколько удобных функций для доступа к random.org .
источник
Я нахожу , что я использую
with()
и всеwithin()
больше и больше. Больше$
не надо засорять мой код, и не нужно начинать прикреплять объекты к пути поиска. А если серьезно, я считаю, что иwith()
т. Д. Делают мои сценарии анализа данных более ясными.> df <- data.frame(A = runif(10), B = rnorm(10)) > A <- 1:10 ## something else hanging around... > with(df, A + B) ## I know this will use A in df! [1] 0.04334784 -0.40444686 1.99368816 0.13871605 -1.17734837 [6] 0.42473812 2.33014226 1.61690799 1.41901860 0.8699079
with()
устанавливает среду, в которой оценивается выражение R.within()
делает то же самое, но позволяет вам изменять объект данных, используемый для создания среды.> df <- within(df, C <- rpois(10, lambda = 2)) > head(df) A B C 1 0.62635571 -0.5830079 1 2 0.04810539 -0.4525522 1 3 0.39706979 1.5966184 3 4 0.95802501 -0.8193090 2 5 0.76772541 -1.9450738 2 6 0.21335006 0.2113881 4
Когда я впервые использовал
within()
это, я не осознавал, что вам нужно выполнить присваивание как часть оцениваемого выражения и присвоить возвращаемый объект (как указано выше), чтобы получить желаемый эффект.источник
Уловка с вводом данных = пакет RGoogleDocs
http://www.omegahat.org/RGoogleDocs/
Я обнаружил, что электронные таблицы Google - отличный способ для всех соавторов быть на одной странице. Кроме того, Google Forms позволяет собирать данные от респондентов и легко записывать их в электронную таблицу Google. Поскольку данные часто меняются и почти никогда не бывают окончательными, для R гораздо предпочтительнее читать электронную таблицу Google напрямую, чем загружать файлы CSV и считывать их.
# Get data from google spreadsheet library(RGoogleDocs) ps <-readline(prompt="get the password in ") auth = getGoogleAuth("me@gmail.com", ps, service="wise") sheets.con <- getGoogleDocsConnection(auth) ts2=getWorksheets("Data Collection Repos",sheets.con) names(ts2) init.consent <-sheetAsMatrix(ts2$Sheet1,header=TRUE, as.data.frame=TRUE, trim=TRUE)
Я не могу вспомнить, какая из следующих команд, кроме одной или двух, занимает несколько секунд.
getGoogleAuth
getGoogleDocsConnection
getWorksheets
источник
Используйте обратные кавычки для ссылки на нестандартные имена.
> df <- data.frame(x=rnorm(5),y=runif(5)) > names(df) <- 1:2 > df 1 2 1 -1.2035003 0.6989573 2 -1.2146266 0.8272276 3 0.3563335 0.0947696 4 -0.4372646 0.9765767 5 -0.9952423 0.6477714 > df$1 Error: unexpected numeric constant in "df$1" > df$`1` [1] -1.2035003 -1.2146266 0.3563335 -0.4372646 -0.9952423
В этом случае также будет работать df [, "1"]. Но внутри формул работают обратные галочки!
> lm(`2`~`1`,data=df) Call: lm(formula = `2` ~ `1`, data = df) Coefficients: (Intercept) `1` 0.4087 -0.3440
[Edit] Дирк спрашивает, зачем давать неверные имена? Я не знаю! Но на практике я, конечно, довольно часто сталкиваюсь с этой проблемой. Например, используя пакет hashape reshape:
> library(reshape) > df$z <- c(1,1,2,2,2) > recast(df,z~.,id.var="z") Aggregation requires fun.aggregate: length used as default z (all) 1 1 4 2 2 6 > recast(df,z~.,id.var="z")$(all) Error: unexpected '(' in "recast(df,z~.,id.var="z")$(" > recast(df,z~.,id.var="z")$`(all)` Aggregation requires fun.aggregate: length used as default [1] 4 6
источник
read.table
когдаcheck.names
ложно, то есть когда вы хотите работать с исходными именами столбцов.Не знаю, насколько это хорошо известно, но я определенно воспользовался преимуществами передачи по ссылке в средах.
zz <- new.env() zz$foo <- c(1,2,3,4,5) changer <- function(blah) { blah$foo <- 5 } changer(zz) zz$foo
В этом примере непонятно, почему это может быть полезно, но если вы передаете большие объекты, это может помочь.
источник
Моя новая любимая вещь - это библиотека foreach. Он позволяет вам делать все приятные вещи, но с несколько более простым синтаксисом:
list_powers <- foreach(i = 1:100) %do% { lp <- x[i]^i return (lp) }
Самое приятное то, что если вы делаете что-то, что на самом деле требует значительного количества времени, вы можете переключиться с
%do%
на%dopar%
(с соответствующей серверной библиотекой) для мгновенного распараллеливания, даже в кластере. Очень красиво.источник
Я занимаюсь основными манипуляциями с данными, поэтому вот две встроенные функции ( преобразование , подмножество ) и одна библиотека ( sqldf ), которые я использую ежедневно.
создать образец данных о продажах
sales <- expand.grid(country = c('USA', 'UK', 'FR'), product = c(1, 2, 3)) sales$revenue <- rnorm(dim(sales)[1], mean=100, sd=10) > sales country product revenue 1 USA 1 108.45965 2 UK 1 97.07981 3 FR 1 99.66225 4 USA 2 100.34754 5 UK 2 87.12262 6 FR 2 112.86084 7 USA 3 95.87880 8 UK 3 96.43581 9 FR 3 94.59259
используйте transform (), чтобы добавить столбец
## transform currency to euros usd2eur <- 1.434 transform(sales, euro = revenue * usd2eur) > country product revenue euro 1 USA 1 108.45965 155.5311 2 UK 1 97.07981 139.2125 3 FR 1 99.66225 142.9157 ...
используйте subset (), чтобы разрезать данные
subset(sales, country == 'USA' & product %in% c(1, 2), select = c('product', 'revenue')) > product revenue 1 1 108.4597 4 2 100.3475
используйте sqldf () для нарезки и агрегирования с SQL
Пакет sqldf предоставляет интерфейс SQL для фреймов данных R
## recast the previous subset() expression in SQL sqldf('SELECT product, revenue FROM sales \ WHERE country = "USA" \ AND product IN (1,2)') > product revenue 1 1 108.4597 2 2 100.3475
Выполните агрегирование или GROUP BY
sqldf('select country, sum(revenue) revenue \ FROM sales \ GROUP BY country') > country revenue 1 FR 307.1157 2 UK 280.6382 3 USA 304.6860
Для более сложных функций map-reduce для фреймов данных ознакомьтесь с пакетом plyr . И если найти себе желание вытащить свои волосы, я рекомендую проверить Манипулирование данными с R .
источник
Подмножества 'x []' усредняются, причем каждое подмножество состоит из наблюдений с одинаковыми уровнями факторов. Использование: ave (x, ..., FUN = mean)
Я использую это все время. (например, в этом ответе здесь так )
источник
Способ ускорить код и исключить циклы for.
вместо циклов for, которые просматривают фрейм данных в поисках значений. просто возьмите подмножество df с этими значениями, намного быстрее.
так что вместо:
for(i in 1:nrow(df)){ if (df$column[i] == x) { df$column2[i] <- y or any other similiar code } }
сделай что-нибудь вроде этого:
эта базовая концепция применяется очень часто и является отличным способом избавиться от циклов for.
источник
Иногда требуется
rbind
несколько фреймов данных.do.call()
позволит вам это сделать (кто-то должен был объяснить это мне, когда я задал этот вопрос при связывании, поскольку его использование не является очевидным).foo <- list() foo[[1]] <- data.frame(a=1:5, b=11:15) foo[[2]] <- data.frame(a=101:105, b=111:115) foo[[3]] <- data.frame(a=200:210, b=300:310) do.call(rbind, foo)
источник
unsplit
.В R программировании (не интерактивные сеансы), я использую
if (bad.condition) stop("message")
в много . Каждая функция начинается с нескольких из них, и, работая над вычислениями, я тоже добавляю их. Полагаю, я привык к использованиюassert()
в C. Преимущества двоякие. Во-первых, с этими проверками намного быстрее получить рабочий код. Во-вторых, что, вероятно, более важно, работать с существующим кодом намного проще, если вы видите эти проверки на каждом экране в редакторе. Вам не придется задаваться вопросомx>0
, или доверять комментарию о том, что это ... вы узнаете с первого взгляда, что это так.PS. мой первый пост здесь. Быть нежным!
источник
stopfifnot(!bad.condition)
более лаконичный.Эта
traceback()
функция необходима, когда у вас где-то есть ошибка, и вы не можете ее сразу понять. Он напечатает трассировку стека, что очень полезно, поскольку R по умолчанию не очень подробный.Затем настройка
options(error=recover)
позволит вам «войти» в функцию, вызывающую ошибку, и попытаться понять, что именно происходит, как если бы вы полностью контролировали это и могли бы указатьbrowser()
в нем.Эти три функции действительно могут помочь отладить ваш код.
источник
options(error=recover)
это мой любимый метод отладки.Я действительно удивлен, что никто не написал о apply, tapply, lapply и sapply. Общее правило, которое я использую при работе с R, заключается в том, что если у меня есть цикл for, который выполняет обработку данных или моделирование, я пытаюсь выделить его и заменить на * apply. Некоторые люди уклоняются от функций * apply, потому что они думают, что можно передавать только функции с одним параметром. Ничего не может быть дальше от истины! Подобно передаче функций с параметрами в качестве объектов первого класса в Javascript, вы делаете это в R с анонимными функциями. Например:
> sapply(rnorm(100, 0, 1), round) [1] 1 1 0 1 1 -1 -2 0 2 2 -2 -1 0 1 -1 0 1 -1 0 -1 0 0 0 0 0 [26] 2 0 -1 -2 0 0 1 -1 1 5 1 -1 0 1 1 1 2 0 -1 1 -1 1 0 -1 1 [51] 2 1 1 -2 -1 0 -1 2 -1 1 -1 1 -1 0 -1 -2 1 1 0 -1 -1 1 1 2 0 [76] 0 0 0 -2 -1 1 1 -2 1 -1 1 1 1 0 0 0 -1 -3 0 -1 0 0 0 1 1 > sapply(rnorm(100, 0, 1), round(x, 2)) # How can we pass a parameter? Error in match.fun(FUN) : object 'x' not found # Wrap your function call in an anonymous function to use parameters > sapply(rnorm(100, 0, 1), function(x) {round(x, 2)}) [1] -0.05 -1.74 -0.09 -1.23 0.69 -1.43 0.76 0.55 0.96 -0.47 -0.81 -0.47 [13] 0.27 0.32 0.47 -1.28 -1.44 -1.93 0.51 -0.82 -0.06 -1.41 1.23 -0.26 [25] 0.22 -0.04 -2.17 0.60 -0.10 -0.92 0.13 2.62 1.03 -1.33 -1.73 -0.08 [37] 0.45 -0.93 0.40 0.05 1.09 -1.23 -0.35 0.62 0.01 -1.08 1.70 -1.27 [49] 0.55 0.60 -1.46 1.08 -1.88 -0.15 0.21 0.06 0.53 -1.16 -2.13 -0.03 [61] 0.33 -1.07 0.98 0.62 -0.01 -0.53 -1.17 -0.28 -0.95 0.71 -0.58 -0.03 [73] -1.47 -0.75 -0.54 0.42 -1.63 0.05 -1.90 0.40 -0.01 0.14 -1.58 1.37 [85] -1.00 -0.90 1.69 -0.11 -2.19 -0.74 1.34 -0.75 -0.51 -0.99 -0.36 -1.63 [97] -0.98 0.61 1.01 0.55 # Note that anonymous functions aren't being called, but being passed. > function() {print('hello #rstats')}() function() {print('hello #rstats')}() > a = function() {print('hello #rstats')} > a function() {print('hello #rstats')} > a() [1] "hello #rstats"
(Для тех, кто следит за #rstats, я также разместил это там).
Помните, используйте apply, sapply, lapply, tapply и do.call! Воспользуйтесь векторизацией R. Вы никогда не должны подходить к кучке кода R и видеть:
N = 10000 l = numeric() for (i in seq(1:N)) { sim <- rnorm(1, 0, 1) l <- rbind(l, sim) }
Мало того, что это не векторизовано, но и структура массива в R не увеличивается, как в Python (удвоение размера, когда пространство заканчивается, IIRC). Таким образом, каждый шаг rbind должен сначала вырасти l настолько, чтобы принять результаты от rbind (), а затем скопировать все содержимое предыдущего l. Ради интереса попробуйте описанное выше в R. Обратите внимание, сколько времени это займет (вам даже не понадобится Rprof или какая-либо функция синхронизации). Тогда попробуй
N=10000 l <- rnorm(N, 0, 1)
Лучше, чем первая версия:
N = 10000 l = numeric(N) for (i in seq(1:N)) { sim <- rnorm(1, 0, 1) l[i] <- sim }
источник
По совету Дирка выкладываю единичные примеры. Я надеюсь, что они не слишком "милые" [умные, но мне все равно] или тривиальные для этой аудитории.
Линейные модели - это хлеб с маслом R. Когда число независимых переменных велико, у каждого есть два варианта. Во-первых, он использует lm.fit (), который получает матрицу проектирования x и ответ y в качестве аргументов, аналогично Matlab. Недостатком этого подхода является то, что возвращаемое значение представляет собой список объектов (подогнанные коэффициенты, остатки и т. Д.), А не объект класса «lm», который можно красиво резюмировать, использовать для прогнозирования, пошагового выбора и т. Д. Второе подход заключается в создании формулы:
> A X1 X2 X3 X4 y 1 0.96852363 0.33827107 0.261332257 0.62817021 1.6425326 2 0.08012755 0.69159828 0.087994158 0.93780481 0.9801304 3 0.10167545 0.38119304 0.865209832 0.16501662 0.4830873 4 0.06699458 0.41756415 0.258071616 0.34027775 0.7508766 ... > (f=paste("y ~",paste(names(A)[1:4],collapse=" + "))) [1] "y ~ X1 + X2 + X3 + X4" > lm(formula(f),data=A) Call: lm(formula = formula(f), data = A) Coefficients: (Intercept) X1 X2 X3 X4 0.78236 0.95406 -0.06738 -0.43686 -0.06644
источник
Вы можете присвоить значение, возвращаемое из блока if-else.
Вместо, например,
condition <- runif(1) > 0.5 if(condition) x <- 1 else x <- 2
ты можешь сделать
x <- if(condition) 1 else 2
Как это работает - глубокая магия.
источник
if-then-else
выражения работают на любом функциональном языке (не путать сif-then-else
операторами ). Очень похоже на тернарный?:
оператор C-подобных языков.Как полный новичок в R и новичок в статистике, я люблю
unclass()
печатать все элементы фрейма данных как обычный список.Очень удобно просматривать полный набор данных за один раз, чтобы быстро выявить любые потенциальные проблемы.
источник
CrossTable()
изgmodels
пакета обеспечивает легкий доступ к кросс-таблицам в стиле SAS и SPSS, а также к обычным тестам (Chisq, McNemar и т. д.). По сути, этоxtabs()
навороченный вывод и некоторые дополнительные тесты, но он упрощает обмен выводами с язычниками.источник
Определенно
system()
. Возможность иметь доступ ко всем инструментам unix (по крайней мере, под Linux / MacOSX) из среды R быстро стала бесценной в моем повседневном рабочем процессе.источник
help(connections)
Подробности и примеры.Вот неприятный обходной путь для преобразования коэффициента в числовой. (Аналогично и для других типов данных)
источник
as.numeric(levels(old.var))[old.var]
Хотя этот вопрос поднимался некоторое время, я недавно обнаружил в блоге SAS и R отличный трюк для использования этой команды
cut
. Команда используется для разделения данных на категории, и я буду использовать набор данных iris в качестве примера и разделить его на 10 категорий:> irisSL <- iris$Sepal.Length > str(irisSL) num [1:150] 5.1 4.9 4.7 4.6 5 5.4 4.6 5 4.4 4.9 ... > cut(irisSL, 10) [1] (5.02,5.38] (4.66,5.02] (4.66,5.02] (4.3,4.66] (4.66,5.02] (5.38,5.74] (4.3,4.66] (4.66,5.02] (4.3,4.66] (4.66,5.02] [11] (5.38,5.74] (4.66,5.02] (4.66,5.02] (4.3,4.66] (5.74,6.1] (5.38,5.74] (5.38,5.74] (5.02,5.38] (5.38,5.74] (5.02,5.38] [21] (5.38,5.74] (5.02,5.38] (4.3,4.66] (5.02,5.38] (4.66,5.02] (4.66,5.02] (4.66,5.02] (5.02,5.38] (5.02,5.38] (4.66,5.02] [31] (4.66,5.02] (5.38,5.74] (5.02,5.38] (5.38,5.74] (4.66,5.02] (4.66,5.02] (5.38,5.74] (4.66,5.02] (4.3,4.66] (5.02,5.38] [41] (4.66,5.02] (4.3,4.66] (4.3,4.66] (4.66,5.02] (5.02,5.38] (4.66,5.02] (5.02,5.38] (4.3,4.66] (5.02,5.38] (4.66,5.02] [51] (6.82,7.18] (6.1,6.46] (6.82,7.18] (5.38,5.74] (6.46,6.82] (5.38,5.74] (6.1,6.46] (4.66,5.02] (6.46,6.82] (5.02,5.38] [61] (4.66,5.02] (5.74,6.1] (5.74,6.1] (5.74,6.1] (5.38,5.74] (6.46,6.82] (5.38,5.74] (5.74,6.1] (6.1,6.46] (5.38,5.74] [71] (5.74,6.1] (5.74,6.1] (6.1,6.46] (5.74,6.1] (6.1,6.46] (6.46,6.82] (6.46,6.82] (6.46,6.82] (5.74,6.1] (5.38,5.74] [81] (5.38,5.74] (5.38,5.74] (5.74,6.1] (5.74,6.1] (5.38,5.74] (5.74,6.1] (6.46,6.82] (6.1,6.46] (5.38,5.74] (5.38,5.74] [91] (5.38,5.74] (5.74,6.1] (5.74,6.1] (4.66,5.02] (5.38,5.74] (5.38,5.74] (5.38,5.74] (6.1,6.46] (5.02,5.38] (5.38,5.74] [101] (6.1,6.46] (5.74,6.1] (6.82,7.18] (6.1,6.46] (6.46,6.82] (7.54,7.9] (4.66,5.02] (7.18,7.54] (6.46,6.82] (7.18,7.54] [111] (6.46,6.82] (6.1,6.46] (6.46,6.82] (5.38,5.74] (5.74,6.1] (6.1,6.46] (6.46,6.82] (7.54,7.9] (7.54,7.9] (5.74,6.1] [121] (6.82,7.18] (5.38,5.74] (7.54,7.9] (6.1,6.46] (6.46,6.82] (7.18,7.54] (6.1,6.46] (5.74,6.1] (6.1,6.46] (7.18,7.54] [131] (7.18,7.54] (7.54,7.9] (6.1,6.46] (6.1,6.46] (5.74,6.1] (7.54,7.9] (6.1,6.46] (6.1,6.46] (5.74,6.1] (6.82,7.18] [141] (6.46,6.82] (6.82,7.18] (5.74,6.1] (6.46,6.82] (6.46,6.82] (6.46,6.82] (6.1,6.46] (6.46,6.82] (6.1,6.46] (5.74,6.1] 10 Levels: (4.3,4.66] (4.66,5.02] (5.02,5.38] (5.38,5.74] (5.74,6.1] (6.1,6.46] (6.46,6.82] (6.82,7.18] ... (7.54,7.9]
источник
Еще одна уловка. Некоторые пакеты, как glmnet, только взять в качестве входов матрицы дизайна и переменный отклик. Если кто-то хочет подогнать модель со всеми взаимодействиями между элементами, он не может использовать формулу «y ~. ^ 2». Использование
expand.grid()
позволяет нам использовать мощные возможности индексирования массивов и векторных операций R.interArray=function(X){ n=ncol(X) ind=expand.grid(1:n,1:n) return(X[,ind[,1]]*X[,ind[,2]]) } > X X1 X2 1 0.96852363 0.33827107 2 0.08012755 0.69159828 3 0.10167545 0.38119304 4 0.06699458 0.41756415 5 0.08187816 0.09805104 > interArray(X) X1 X2 X1.1 X2.1 1 0.938038022 0.327623524 0.327623524 0.114427316 2 0.006420424 0.055416073 0.055416073 0.478308177 3 0.010337897 0.038757974 0.038757974 0.145308137 4 0.004488274 0.027974536 0.027974536 0.174359821 5 0.006704033 0.008028239 0.008028239 0.009614007
источник
model.matrix
?Один из моих любимых, если не сказать несколько неортодоксальных приемов - это использование
eval()
иparse()
. Этот пример, возможно, показывает, как это может быть полезноNY.Capital <- 'Albany' state <- 'NY' parameter <- 'Capital' eval(parse(text=paste(state, parameter, sep='.'))) [1] "Albany"
Ситуации такого типа возникают чаще, и их использование
eval()
иparse()
может помочь в их решении. Конечно, я приветствую любые отзывы об альтернативных способах написания кода.источник
set.seed()
устанавливает состояние генератора случайных чисел.Например:
> set.seed(123) > rnorm(1) [1] -0.5604756 > rnorm(1) [1] -0.2301775 > set.seed(123) > rnorm(1) [1] -0.5604756
источник
Для тех, кто пишет на C, вызов из R:
.Internal(inspect(...))
удобен. Например:> .Internal(inspect(quote(a+2))) @867dc28 06 LANGSXP g0c0 [] @8436998 01 SYMSXP g1c0 [MARK,gp=0x4000] "+" @85768b0 01 SYMSXP g1c0 [MARK,NAM(2)] "a" @8d7bf48 14 REALSXP g0c1 [] (len=1, tl=0) 2
источник
d = '~ / Код R / Библиотека /'
files = list.files (d, '. r $')
for (f в файлах) {if (! (f == 'mysource.r')) {print (paste ('Sourcing', f)) source (paste (d, f, sep = ''))}}
Я использую приведенный выше код для получения всех файлов в каталоге при запуске с различными служебными программами, которые я использую в моем интерактивном сеансе с R. Я уверен, что есть лучшие способы, но я считаю его полезным для своей работы. Строка, которая делает это, выглядит следующим образом.
источник ("~ / R Code / Library / mysource.r")
источник
Для выполнения операции с рядом переменных в кадре данных. Это украдено из subset.data.frame.
get.vars<-function(vars,data){ nl <- as.list(1L:ncol(data)) names(nl) <- names(data) vars <- eval(substitute(vars), nl, parent.frame()) data[,vars] #do stuff here } get.vars(c(cyl:hwy,class),mpg)
источник
get.vars
не перепрыгивая через множество обручей.Я уже публиковал это однажды, но я так часто им пользуюсь, что подумал, что выложу еще раз. Это всего лишь небольшая функция, возвращающая имена и номера позиций data.frame. В этом нет ничего особенного, чтобы быть уверенным, но я почти никогда не прохожу через сеанс, не используя его несколько раз.
##creates an object from a data.frame listing the column names and location
namesind = function (df) {
temp1=names(df) temp2=seq(1,length(temp1)) temp3=data.frame(temp1,temp2) names(temp3)=c("VAR","COL") return(temp3) rm(temp1,temp2,temp3)
}
ni <- namesind
источник
data.frame(VAR = names(df), COL = seq_along(df))