скрытие личных функций в R - PullRequest
33 голосов
/ 28 января 2011

У меня есть несколько вспомогательных функций в моем .Rprofile, например, эта удобная функция для возврата размера объектов в памяти .Иногда мне нравится очищать мое рабочее пространство без перезапуска, и я делаю это с rm(list=ls()), который удаляет все мои созданные пользователем объекты и мои пользовательские функции.Я действительно хотел бы не взорвать мои пользовательские функции.

Одним из способов решения этой проблемы является создание пакета с моими пользовательскими функциями, чтобы мои функции оказались в своем собственном пространстве имен.Это не особенно сложно, но есть ли более простой способ гарантировать, что пользовательские функции не будут уничтожены функцией rm ()?

Ответы [ 7 ]

35 голосов
/ 28 января 2011

Объедините attach и sys.source для источника в среду и присоедините эту среду. Здесь у меня есть две функции в файле my_fun.R:

foo <- function(x) {
    mean(x)
}

bar <- function(x) {
    sd(x)
}

Прежде чем загрузить эти функции, они явно не найдены:

> foo(1:10)
Error: could not find function "foo"
> bar(1:10)
Error: could not find function "bar"

Создайте окружение и поместите в него файл:

> myEnv <- new.env()
> sys.source("my_fun.R", envir = myEnv)

Все еще не видно, поскольку мы ничего не прикрепили

> foo(1:10)
Error: could not find function "foo"
> bar(1:10)
Error: could not find function "bar"

и когда мы делаем это, они видимы, и поскольку мы прикрепили копию окружения к пути поиска, функции выживают, будучи rm() -ed:

> attach(myEnv)
> foo(1:10)
[1] 5.5
> bar(1:10)
[1] 3.027650
> rm(list = ls())
> foo(1:10)
[1] 5.5

Я все еще думаю, что вам будет лучше с вашим личным пакетом, но в то же время вышеперечисленного может быть достаточно. Просто помните, что копия в пути поиска - это просто копия . Если функции довольно стабильны, и вы не редактируете их, вышеописанное может быть полезным, но, вероятно, это более хлопотно, чем стоит, если вы разрабатываете функции и модифицируете их.

Второй вариант - просто назвать их все .foo вместо foo, так как ls() не будет возвращать объекты с такими именами, если не установлен аргумент all = TRUE:

> .foo <- function(x) mean(x)
> ls()
character(0)
> ls(all = TRUE)
[1] ".foo"         ".Random.seed"
21 голосов
/ 28 января 2011

Вот два способа:

1) Пусть каждое из имен ваших функций начинается с точки, например, .f вместо f. ls не будет перечислять такие функции, если вы не используете ls(all.names = TRUE), поэтому они не будут переданы вашей команде rm.

или

2) Поместите это в свой .Rprofile

attach(list(
   f = function(x) x, 
   g = function(x) x*x
), name = "MyFunctions")

Функции будут отображаться как компонент с именем "MyFunctions" в вашем списке поиска, а не в вашем рабочем пространстве, и они будут доступны почти так же, как если бы они были в вашем рабочем пространстве. search() отобразит ваш список поиска, а ls("MyFunctions") отобразит названия функций, которые вы добавили. Поскольку они не находятся в вашей рабочей области, обычно используемая вами команда rm не удалит их. Если вы хотите удалить их, используйте detach("MyFunctions").

10 голосов
/ 28 января 2011

Ответ Гэвина замечательный, и я просто проголосовал за него. Просто для полноты позвольте мне добавить следующее:

R> q("no")

с последующим

M-x R

для создания нового сеанса --- который перечитывает .Rprofile. Легко, быстро и дешево.

Кроме этого, частные пакеты - путь в моей книге.

3 голосов
/ 28 января 2011

Другая альтернатива: хранить функции в отдельном файле, который находится в .RProfile. Вы можете повторно получить содержимое непосредственно из R на досуге.

2 голосов
/ 21 февраля 2011

Я обнаружил, что часто моя среда R загромождается различными объектами, когда я создаю или отлаживаю функцию. Мне нужен был способ эффективно защитить окружающую среду от этих объектов, сохранив при этом личные функции.

Простая функция ниже была моим решением. Это делает 2 вещи: 1) удаляет все нефункциональные объекты, которые не начинаются с заглавной буквы, а затем 2) сохраняет среду в виде файла RData

(требуется пакет R.oo)

cleanup=function(filename="C:/mymainR.RData"){  
library(R.oo)  
# create a dataframe listing all personal objects
everything=ll(envir=1)
#get the objects that are not functions
nonfunction=as.vector(everything[everything$data.class!="function",1])
#nonfunction objects that do not begin with a capital letter should be deleted
trash=nonfunction[grep('[[:lower:]]{1}',nonfunction)]
remove(list=trash,pos=1)
#save the R environment
save.image(filename)
print(paste("New, CLEAN R environment saved in",filename))
}

Чтобы использовать эту функцию, всегда нужно соблюдать 3 правила:
1) Храните все данные вне R.
2) Используйте имена, которые начинаются с заглавной буквы для нефункциональных объектов, которые я хочу сохранить постоянно доступными.
3) Устаревшие функции должны быть удалены вручную с помощью команды rm.

Очевидно, что это не общее решение для всех ... и может иметь катастрофические последствия, если вы не будете соблюдать правила № 1 и № 2. Но у него есть ряд преимуществ: а) боязнь того, что мои данные будут очищены с помощью cleanup (), заставляет меня дисциплинировать использование R исключительно в качестве процессора, а не базы данных, б) моя основная среда R настолько мала, что я могу создавать резервные копии в виде вложений электронной почты , c) новые функции автоматически сохраняются (мне не нужно вручную управлять списком личных функций), и d) все изменения ранее существовавших функций сохраняются. Конечно, лучшее преимущество - самое очевидное ... Мне не нужно тратить время на выполнение ls () и просмотр объектов, чтобы решить, должны ли они быть rm'd.

Даже если вас не волнует специфика моей системы, функция "ll" в R.oo очень полезна для такого рода вещей. Его можно использовать для реализации практически любого набора правил очистки, которые соответствуют вашему личному стилю программирования.

Патрик Мор

0 голосов
/ 18 сентября 2015

Подобно ответу Гэвина, следующее загружает файл функций, но не оставляя вокруг себя лишний объект среды:

if('my_namespace' %in% search()) detach('my_namespace'); source('my_functions.R', attach(NULL, name='my_namespace')) 

Это удаляет старую версию пространства имен, если она была присоединена (полезно для разработки), затем присоединяет пустую новую среду с именем my_namespace и источники my_functions.R в нее.Если вы не удалите старую версию, вы создадите несколько подключенных сред с одним и тем же именем.

Если вы хотите узнать, какие функции были загружены, посмотрите на вывод для

ls('my_namespace')

Для выгрузки используйте

detach('my_namespace')

Эти прикрепленные функции, как и пакет, не будут удалены rm(list=ls()).

0 голосов
/ 02 августа 2013

nth, быстрый и грязный вариант, будет использовать lsf.str() при использовании rm(), чтобы получить все функции в текущем рабочем пространстве.... и пусть вы называете функции по своему желанию.

pattern <- paste0('*',lsf.str(), '$', collapse = "|")
rm(list = ls()[-grep(pattern, ls())])

Я согласен, это может быть не самой лучшей практикой, но это делает работу!(и я все равно должен выборочно убирать за собой ...)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...