2013-12-20 2 views
5

Это моя первая неделя, работающая с R, и есть одна вещь о функции, которой я не могу управлять.Верните DataFrame из функции и сохраните ее в рабочей области

df <- data.frame(a = c(1:10), 
      b = c("a", "a", "b", "c", "c", "b", "a", "c", "c", "b")) 

testF = function(select) { 
dum = subset(df, b == select) 
} 

lapply(unique(df$b), testF) 

Эта функция теперь просто печатает наборы данных на экране. Но я хотел бы сохранить результаты в виде отдельных кадров данных в моей рабочей области. В этом примере это даст три кадра данных; a, b и c.

Благодарим за помощь.

+0

Запись строки «дум» в последней строке функции, и он должен вернуть объект из функции. –

+1

Прочитайте 'help (" function ")'. Вы также должны прочитать 'help (" subset ")', который явно запрещает использование внутренних функций 'subset'. – Roland

+0

@ Роланд, что является примером одного из тех непредвиденных последствий? – rawr

ответ

2

У Roland есть правильное решение для конкретной проблемы: более split() не требуется. Просто чтобы убедиться: split() возвращает список. Для того, чтобы получить отдельные кадры данных вы рабочее пространство, вы делаете:

list2env(split(df,df$b),.GlobalEnv) 

Или, используя назначения:

tmp <- split(df,df$b) 
for(i in names(tmp)) assign(i,tmp[[i]]) 

А слово на подмножестве

При этом, некоторые более подробно почему ваша функция проста. Прежде всего, в ?subset вы читаете:

Предупреждение

Это удобная функция предназначена для использования в интерактивном режиме. Для программирования лучше использовать стандартные функции подмножества, такие как [, и, в частности, нестандартная оценка подмножества аргументов может иметь непредвиденные последствия.

Переведено на: Никогда в жизни не используется subset() внутри функции.


Слова о возвращении значения из функции

Далее в том, что функция всегда возвращает результат:

  • если используются return() заявления, оно возвращает то, что дано как аргумент return().
  • В противном случае он возвращает результат последней строки.

В вашем случае последняя строка содержит задание. Теперь присваивание также возвращает значение, но вы его не видите. Он возвращается invisibly. Вы можете увидеть его, заключая его в круглые скобки, например:

> x <- 10 
> (x <- 20) 
[1] 20 

Это абсолютно не нужно. Это причина, по которой ваша функция работает, когда используется в lapply() (lapply ловит невидимый результат), но не даст вам никакого (видимого) вывода при использовании в командной строке. Вы можете захватить его, хотя:

> testF("b") 
> x <- testF("b") 
> x 
    a b 
3 3 b 
6 6 b 
10 10 b 

Назначение в функции не имеет смысла: либо вернуться dum явно, или просто уронить задание ALLtogether


Исправляющие функцию

Итак, учитывая, что это всего лишь пример, и реальная проблема не будет решена простым использованием split(), ваша функция будет:

testF <- function(select) { 
    dum <- df[df$b=select,] 
    return(dum) 
} 

или просто:

testF <- function(select){ 
    df[df$b=select,] 
} 
+1

Спасибо за вашу всестороннюю и детальную реакцию. И я никогда больше никогда не буду использовать подмножество() снова, даже внешние функции. – user3122822

1

Ваша функция требует возвращаемого значения. См. help("function").

Однако, для вашего конкретного случая вы можете просто использовать split:

split(df, df$b) 

$a 
    a b 
1 1 a 
2 2 a 
7 7 a 

$b 
    a b 
3 3 b 
6 6 b 
10 10 b 

$c 
    a b 
4 4 c 
5 5 c 
8 8 c 
9 9 c 
+1

Может быть интересно отметить, что 'split()' возвращает список, который вы можете использовать 'assign()' для создания отдельных кадров данных и что это вообще плохая идея. Создание разных кадров данных, когда вы можете просто работать со списком. –

+1

Или 'list2env', если у вас есть список и по какой-то странной причине« должен »поместить его содержимое в глобальную среду. – Roland

+0

Большое спасибо за помощь. Я буду использовать split и проделать свой путь через страницы справки. – user3122822

1

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

df <- data.frame(a = c(1:10), 
      b = c("a", "a", "b", "c", "c", "b", "a", "c", "c", "b")) 

testF = function(select) { 
    dum = subset(df, b == select) 
    dum        # you need to return the data frame resulting from the subset back out of the function 
} 

my.list = lapply(unique(df$b), testF) 
names(my.list) = unique(df$b)   # set the names of the list elements to the subsets they represent (a,b,c) 
list2env(my.list,envir = .GlobalEnv) # copy the data frames from the list to the Global Environment 

Если у вас простой пример, как тот, который вы изобразить вы могли бы получить доступ к элементам списка один за другим, как следует и присвоить каждому переменной.

a = my.list[[1]] 
b = my.list[[2]] 
c = my.list[[3]] 

Наконец, можно определить функцию инлайн такого и сделать использование (удивительного) data.table пакета, тем самым избегая использование подмножества:

library(data.table) 
dt <- data.table(a = c(1:10), 
      b = c("a", "a", "b", "c", "c", "b", "a", "c", "c", "b")) 
my.list = lapply(unique(dt$b), function(select) { dt[b == eval(select)]}) 

Надеется, что это помогает.

+1

Как указано в '? Subset', вы НЕ должны использовать подмножество внутри функции. подмножество - функция удобства. Используйте 'df [df $ b == select,]', чтобы в какой-то момент избежать огромных проблем. –

+0

Отмеченный @ Joris Meys, я включил пример внизу, который избегает этого. Должен ли мой ответ удалить ссылку 'subset'? Я не уверен в хорошей практике ответа на эти вопросы. Кроме того, я включил пример 'data.table' в отличие от' df [df $ b == select,] 'чисто, потому что я считаю, что пакет настолько хорош (скорость, память, функциональность), что он платит, чтобы начать использовать его над' data.frame' на ранней стадии! –

+1

'data.table' еще более кратким, если вы сначала установили ключ:' setkey (dt, "b"); lapply (unique (dt $ b), function (x) dt [x]) ' – A5C1D2H2I1M1N2O1R2T1

Смежные вопросы