Возвращает фрейм данных из функции

#r #function #dataframe

#r #функция #фрейм данных

Вопрос:

У меня есть следующий код внутри функции

 Myfunc<- function(directory, MyFiles, id = 1:332) {
# uncomment the 3 lines below for testing
#directory<-"local"
#id=c(2, 4)
#MyFiles<-c(f2.csv,f4.csv)
idd<-id

df2 <- data.frame()

for(i in 1:length(idd)) {
  EmptyVector <- read.csv(MyFiles[i])  
  comp_cases[i]<-sum(complete.cases(EmptyVector))
  print(comp_cases[[i]])
  id=idd[i]
  ret2=comp_cases[[i]]
  df2<-rbind(df2,data.frame(id,ret2))
 }
print(df2)
return(df2)
}
  

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

 > df2
 id ret2
1 2  994
2 4  7112
  

Однако, когда я пытаюсь вернуть df2 фрейм данных из функции, он возвращает только 1-ю строку, игнорируя все остальные значения. Моя проблема в том, что он работает внутри функции для различных значений, которые я пробовал (открытие нескольких файлов с различными комбинациями), а не когда я пытаюсь вернуть фрейм данных. Может кто-нибудь помочь, пожалуйста. Заранее большое спасибо.

Комментарии:

1. Как вы вызываете свою функцию?

Ответ №1:

Если я вас правильно понимаю, вы пытаетесь создать фрейм данных с количеством завершенных обращений для каждого id . Предположим, что ваши файлы представляют собой имена с идентификаторами, подобными указанным вами (например f2.csv ), вы можете упростить свою функцию следующим образом:

 myfunc <- function(directory, id = 1:332) {
  y <- vector()
  for(i in 1:length(id)){
    x <- id
    y <- c(y, sum(complete.cases(
      read.csv(as.character(paste0(directory,"/","f",id[i],".csv"))))))
  }
  df <- data.frame(x, y)
  colnames(df) <- c("id","ret2")
  return(df)
}
  

Вы можете вызвать эту функцию следующим образом:

 myfunc("name-of-your-directory",25:87)
  

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

  1. Вам нужен вектор идентификаторов, это делается с помощью x <- id
  2. Для каждого id вы хотите количество завершенных обращений. Чтобы получить это, вы должны сначала прочитать файл. Это делается с помощью read.csv(as.character(paste0(directory,"/","f",id[i],".csv"))) . Чтобы получить количество полных обращений к этому файлу, вы должны обернуть read.csv код внутри sum и complete.cases .
  3. Теперь вы хотите добавить это число к вектору. Поэтому вам нужен пустой вектор ( y <- vector() ), к которому вы можете добавить количество завершенных обращений с шага 2. Это делается путем переноса кода с шага 2 внутрь y <- c(y, "code step 2") . При этом вы добавляете количество полных обращений для каждого id к вектору y .
  4. Последним шагом является объединение этих двух векторов в фрейм данных с df <- data.frame(x, y) помощью и присвоение некоторого значения colnames .

Включив шаги 1, 2 и 3 (кроме y <- vector() части) в цикл for, вы можете перебирать список указанных идентификаторов. Создание пустого вектора с y <- vector() помощью должно быть выполнено перед циклом for, чтобы цикл for мог добавлять значения y .

Комментарии:

1. @Japp — Это отлично сработало. Код намного чище. Да, я пытался вернуть фрейм данных полных обращений с идентификатором. Если вы скажете мне, где я ошибся, это все равно поможет.

2. @user3127034 — Основная часть, в которой вы ошиблись, — это включение Myfiles параметра в вашу функцию. Это было не нужно, поскольку все ваши имена файлов имеют одинаковую структуру и могут быть получены из идентификаторов. Я добавил объяснение. Я надеюсь, что это поможет.

Ответ №2:

Это на самом деле довольно легко обойти, изменив область видимости.

Проблема в том, что сначала вы создаете исходный фрейм данных как локальную переменную, затем вы просто меняете местами строки, так что в итоге вы получите только первый и последний результаты в фрейме данных.

Когда я создаю цикл for с помощью R и хочу добавить результаты последовательных запросов и т.д. для некоторого начального фрейма данных я делаю это:

 function(<some_args>){ 
main_dataframe <<- do something to generate the first set of results from 
whatever you want to iterate, like 1:10, a given list, etc. and create the 
initial dataframe from the first iteration and use the global assignment 
('<<-'), not '<-' or '='

main_dataframe <<- do_something(whatever_you're_iterating_over[1])

for (i in 2:length(whatever_you're_iterating_over)) {
next_dataframe = do_something(whatever_you're_iterating_over[i])

main_dataframe <<- rbind(main_dataframe, next_dataframe)
    }
}
  

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

Комментарии:

1. спасибо за упоминание <<- глобального оператора присваивания. Это было полезно в моем контексте