Итерация / цикл по списку - PullRequest
2 голосов
/ 15 января 2020

У меня есть некоторые данные на улицах, и я запустил этот код R, чтобы получить содержимое 38 CSV-файлов в списке (больше файлов будет добавлено в будущем):

    common_path  <- "0_data/source_data/DB/Speed/"
    csv_files <- list.files(
    path = common_path,        # directory to search within
    pattern = ".*(1|2).*csv$", # 
    recursive = TRUE,          # search subdirectories
    full.names = TRUE          # return the full path
    )
    data_lst = lapply(csv_files, read.csv2)

Их головы, которые выглядят как это:

Пример данных

Вот заголовок фрейма данных в воспроизводимом формате:

structure(list(typ = c(100L, 100L, 100L, 100L, 100L, 100L, 100L, 
100L, 100L, 1L, 1L, 1L, 1L, 1L, 1L), date.and.time = structure(c(1L, 
1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 2L, 3L, 4L, 5L, 6L, 7L), .Label = c("2019/11/07 18:07:27.000", 
"2019/11/07 18:07:36.290", "2019/11/07 18:07:40.030", "2019/11/07 18:07:41.930", 
"2019/11/07 18:07:43.720", "2019/11/07 18:07:46.380", "2019/11/07 18:07:54.010"
), class = "factor"), speed..km.h. = c(NA, NA, NA, NA, NA, NA, 
NA, NA, NA, 42L, 44L, 43L, 42L, 41L, 43L), length..m. = c(NA, 
NA, NA, NA, NA, NA, NA, NA, NA, 3.2, 4.2, 3.2, 3.9, 3.7, 3.2), 
    range..m. = c(NA, NA, NA, NA, NA, NA, NA, NA, NA, 0L, 0L, 
    0L, 0L, 0L, 0L), notes = c("Serial No = 1", "Direction = NORTH", 
    "Counting type = SINGLE LANE", "Ref count sense = IN", "Install height = 42 decimeter", 
    "Axis distance = 58 decimeter", "Road type = STANDARD", "Road slope = FLAT", 
    "Start of campain", "", "", "", "", "", "")), row.names = c("1", 
"2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", 
"14", "15"), class = "data.frame")

Что я хочу сделать is:

  • Получить информацию о первых 9 строках из столбца «заметки»

  • Добавить информацию из столбца «заметки» отдельно переменные

  • После этого удалите первые 9 строк или все строки, в которых столбцы "typ" == 100

Я могу сделать это с помощью Рука для объекта в списке без проблем, как в коде ниже:

data_lst[[1]]$serial <- data_lst[[1]]$notes[1]
data_lst[[1]]$direction <- data_lst[[1]]$notes[2]
data_lst[[1]]$lane <- data_lst[[1]]$notes[3]
data_lst[[1]]$install_height <- data_lst[[1]]$notes[5]
data_lst[[1]]$axis <- data_lst[[1]]$notes[6]
data_lst[[1]]$notes <- NULL 
data_lst[[1]] <- data_lst[[1]][-c(1:9),]

Но проблемы возникают, когда я пытаюсь l oop этот процесс, так как я очень неопытен с циклами. Я сделал что-то вроде этого,

for(i in data_lst){
  data_lst[[i]]$serial <- data_lst[[i]]$notes[1]
}

, чтобы получить "серийную" информацию из моих данных, но я получил эту ошибку:

error:
in data_lst[[i]] : invalid subscript type 'list'

Любая помощь горячо приветствуется:)

Ответы [ 3 ]

1 голос
/ 15 января 2020

в for-l oop, вы всегда должны указывать, где l oop должен начинаться и где он должен заканчиваться. Вы хотите перебрать каждый элемент в списке, что означает, что вам нужно for (i in seq_along(data_lst)). Выполнение seq_along(data_lst) создаст последовательность от 1 до количества элементов в списке.

1 голос
/ 15 января 2020

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

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

change_data_frame_to_named_list <- function(old_frame)
{
  return(list(serial         = old_frame$notes[1],
              direction      = old_frame$notes[2],
              lane           = old_frame$notes[3],
              install_height = old_frame$notes[5],
              xaxis          = old_frame$notes[6],
              data           = old_frame[-which(old_frame$type == 100), -6]
              ))
}

Теперь все, что вам нужно сделать, это применить эту функцию ко всем элементам в вашем списке. Самый идиоматический c способ сделать это в R - это вообще не использовать al oop, а lapply (сокращение от списка применяется). Он принимает список в качестве первого аргумента и функцию, которую вы sh применяете к каждому элементу в качестве второго аргумента.

Это означает, что вы можете просто сделать это:

result <- lapply(data_lst, change_data_frame_to_named_list)

Это эквивалентно зацикленной версии, но оно короче и аккуратнее.

Если вы действительно хотите сделать это как al oop, эквивалент будет:

result <- list()
for (i in seq_along(data_lst))
{
  result[[i]] = change_data_frame_to_named_list(data_lst[[i]])
}

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

EDIT


ОП запросил аналогичный метод, который возвращает данные в формате, который он уже сделал, с его рукописным l oop. Вот как это можно сделать. Поскольку логика c была отделена от функции, нам нужно только изменить саму функцию:

change_data_frame <- function(old_frame)
{
  old_frame$serial         <- old_frame$notes[1]
  old_frame$direction      <- old_frame$notes[2]
  old_frame$lane           <- old_frame$notes[3]
  old_frame$install_height <- old_frame$notes[5]
  old_frame$xaxis          <- old_frame$notes[6]
  old_frame$notes          <- NULL

  return(old_frame[-which(old_frame$typ == 100),])    
}

# Now you just do as you did before
result <- lapply(data_lst, change_data_frame)

# and to get all dfs into one big data frame...
do.call("rbind", result)
1 голос
/ 15 января 2020

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

> l = list("apple", "banana", "carrot")
> l
[[1]]
[1] "apple"

[[2]]
[1] "banana"

[[3]]
[1] "carrot"

> for(p in l) print(p)
[1] "apple"
[1] "banana"
[1] "carrot"
> for(i in seq_along(l)) print(i)
[1] 1
[1] 2
[1] 3
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...