Использование цикла for в R для разделения фрейма данных на несколько фреймов - PullRequest
0 голосов
/ 21 ноября 2018

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

split_part0 <- split(PART0_DF, PART0_DF$sysid)

Теперь я хочу сделать что-то вроде

for(i in 1:120){ 
sys[i] <- as.data.frame(split_part0[[i]])}

Таким образом, у меня есть 120 фреймов данных с уникальными именами фреймов, которые я могу использовать для дальнейшего анализа,Возможно ли использование цикла for в данном конкретном случае?Если да, какие еще команды я могу использовать?Фиктивные данные для PART0_DF:

 Date      sysid   power   temperature
 1.1.2018    1     1000       14
 2.1.2018    1     1200       16
 3.1.2018    1      800       18
 1.1.2018    2     1500        8
 2.1.2018    2      800       18
 3.1.2018    2     1300       11

Я хочу, чтобы вывод был похож на

     >>sys1
     Date      sysid   power   temperature
     1.1.2018    1     1000     14
     2.1.2018    1     1200     16
     3.1.2018    1      800     18
     >>sys2
     1.1.2018    2     1500      8
     2.1.2018    2      800     18
     3.1.2018    2     1300     11

Ответы [ 2 ]

0 голосов
/ 21 ноября 2018

Другой вариант - использовать функцию by():

df <- data.frame(
  Date = c("1.1.2018",  "2.1.2018", "3.1.2018", "1.1.2018", "2.1.2018", "3.1.2018"),
  sysid = c(1, 1, 1, 2, 2, 2),
  power = c(1000, 1200, 800, 1500, 800, 1300)
  )
df
  Date sysid power
1 1.1.2018     1  1000
2 2.1.2018     1  1200
3 3.1.2018     1   800
4 1.1.2018     2  1500
5 2.1.2018     2   800
6 3.1.2018     2  1300

Теперь разделите df на столько фреймов данных, сколько у вас есть (уникальных) sysid значений, используя by() и вызываяunique:

df_list <- by(df, df$sysid, function(unique) unique)
df_list
df$sysid: 1
      Date sysid power
1 1.1.2018     1  1000
2 2.1.2018     1  1200
3 3.1.2018     1   800
---------------------------------------------------------------------------------------------- 
df$sysid: 2
      Date sysid power
4 1.1.2018     2  1500
5 2.1.2018     2   800
6 3.1.2018     2  1300
0 голосов
/ 21 ноября 2018

Простой способ сделать это - создать факторный вектор, добавив строку sys к номерам идентификаторов и используя ее для разделения данных.Нет необходимости использовать цикл for() для получения желаемого результата, поскольку результатом split() является список фреймов данных, когда вход, который нужно разделить, является фреймом данных.

Значение коэффициента используется для именования каждого элемента в списке, сгенерированном split().В случае OP, поскольку sysid является числовым и начинается с 1, не очевидно, что номера идентификаторов используются для именования результирующих кадров данных в списке, как объяснено в справке для split().

Используя данные из OP, мы проиллюстрируем, как использовать столбец sysid для создания факторной переменной, которая объединяет строку sys со значениями id и разделяет ее на список фреймов данных.к которому можно получить доступ по имени.

rawData <- "Date      sysid   power   temperature
 1.1.2018    1     1000       14
 2.1.2018    1     1200       16
 3.1.2018    1      800       18
 1.1.2018    2     1500        8
 2.1.2018    2      800       18
 3.1.2018    2     1300       11"

data <- read.table(text = rawData,header=TRUE)
sysidName <- paste0("sys",data$sysid)

splitData <- split(data,sysidName)

splitData

... и вывод:

> splitData
$`sys1`
      Date sysid power temperature
1 1.1.2018     1  1000          14
2 2.1.2018     1  1200          16
3 3.1.2018     1   800          18

$sys2
      Date sysid power temperature
4 1.1.2018     2  1500           8
5 2.1.2018     2   800          18
6 3.1.2018     2  1300          11

>

На этом этапе можно получить доступ к отдельным фреймам данных в списке с помощью формы $ оператора извлечения:

> splitData$sys1
      Date sysid power temperature sysidName
1 1.1.2018     1  1000          14      sys1
2 2.1.2018     1  1200          16      sys1
3 3.1.2018     1   800          18      sys1
>

Также с помощью функции names() можно получить вектор всех именованных элементов в списке фреймов данных.

> names(splitData)
[1] "sys1" "sys2"
> 

Повторяя основную точку в верхней части ответа, когда split() используется с фреймом данных, результирующий список представляет собой список объектов типа data.frame().Например:

> str(splitData["sys1"])
List of 1
 $ sys1:'data.frame':   3 obs. of  4 variables:
  ..$ Date       : Factor w/ 3 levels "1.1.2018","2.1.2018",..: 1 2 3
  ..$ sysid      : int [1:3] 1 1 1
  ..$ power      : int [1:3] 1000 1200 800
  ..$ temperature: int [1:3] 14 16 18
>

Если необходимо использовать цикл for() ...

Поскольку ОП спросил, можно ли решить проблему с помощью цикла for(), ответ будет следующим:"да."

# create a vector containing unique values of sysid
ids <- unique(data$sysid)
# initialize output data frame list 
dfList <- list() 
# loop thru unique values and generate named data frames in list() 
for(i in ids){
     dfname <- paste0("sys",i)
     dfList[[dfname]] <- data[data$sysid == i,]
}
dfList 

... и вывод:

> for(i in ids){
+      dfname <- paste0("sys",i)
+      dfList[[dfname]] <- data[data$sysid == i,]
+ }
> dfList
$`sys1`
      Date sysid power temperature
1 1.1.2018     1  1000          14
2 2.1.2018     1  1200          16
3 3.1.2018     1   800          18

$sys2
      Date sysid power temperature
4 1.1.2018     2  1500           8
5 2.1.2018     2   800          18
6 3.1.2018     2  1300          11

Выбор «лучшего» ответа

Между split(), for() и другим ответом с использованиемby(), как выбрать лучший ответ?

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

Мы можем использовать пакет microbenchmark для сравнения производительности трех различных подходов.

split() производительность

library(microbenchmark)
> microbenchmark(splitData <- split(data,sysidName),unit="us")
Unit: microseconds
                                expr     min      lq     mean   median       uq     max neval
 splitData <- split(data, sysidName) 144.594 147.359 185.7987 150.1245 170.4705 615.507   100
> 

for() производительность

> microbenchmark(for(i in ids){
+      dfname <- paste0("sys",i)
+      dfList[[dfname]] <- data[data$sysid == i,]
+ },unit="us")
Unit: microseconds
                                                                                              expr      min       lq     mean
 for (i in ids) {     dfname <- paste0("sys", i)     dfList[[dfname]] <- data[data$sysid == i, ] } 2643.755 2857.286 3457.642
   median       uq      max neval
 3099.064 3479.311 8511.609   100
>

by() производительность

> microbenchmark(df_list <- by(df, df$sysid, function(unique) unique),unit="us")
Unit: microseconds
                                                 expr     min       lq     mean   median       uq      max neval
 df_list <- by(df, df$sysid, function(unique) unique) 256.791 260.5445 304.9296 275.9515 309.5325 1218.372   100
>

... и победитель:

split() со средним временем выполнения 186 микросекунд против 305 микросекунд для by() и колоссальные 3458 микросекунд для циклического подхода for().

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