Чтение в .csv, содержащем векторы (c (x, y)) в R

#r #csv

#r #csv

Вопрос:

Я в некотором затруднении. У меня есть куча (тысячи) CSV-файлов, где несколько строк содержат вектор чисел вместо одного значения, которое мне нужно прочитать в tibble или фрейм данных с вектором в качестве символа для дальнейшей обработки. Например:

 "col1","col2","col3"
"a",1,integer(0)
"c",c(3,4),5
"e",6,7
 

должно закончиться как

   col1   col2        col3     
  <chr>   <chr>    <chr>   
1 a         1          integer(0)  
2 c         c(3,4)     5
3 e         7          7
 

Вектор всегда находится только в «col2» и содержит целые числа. Вектор обычно содержит 2 записи, но может быть и больше. На самом деле в середине есть два столбца, которые могут содержать несколько записей, но я знаю позиции обоих.

Я не могу понять, как успешно прочитать их в R. read.csv или read_csv, похоже, не могут с ними справиться. Есть ли способ, которым я мог бы читать в файлах построчно (к счастью, они не длинные) и eval() строку, возможно, перед разделением на запятые? Я подумал о замене c( на "c( и ) )" в bash перед чтением файлов (и должен буду сделать это для integer( .

В качестве альтернативы, я подумал о разделении .csv в bash на те, которые содержат «нормальные» строки, и те, которые содержат векторы (grep c( ), но я не уверен, как затем вложить 2:length(-1) столбцов обратно в вектор.

Однако я бы определенно предпочел метод, который был автономным в R. Любые идеи приветствуются!

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

1. пожалуйста, отредактируйте Q, чтобы показать требуемый результат из вашего образца ввода. Пожалуйста, не отвечайте в комментариях. Удачи.

2. В вашем вопросе не указано, что вы хотите сделать с вектором (например, NA, первый элемент, 0 и т. Д.) Функция read.csv приведет столбец, содержащий c (3,4), в качестве символьного вектора.

3. @andrea, read.csv работает лучше, чем read_csv, но он переносит лишнее в следующую строку, если это имеет смысл.

4. Ронакшах, спасибо, что уловил это! Просто опечатка.

Ответ №1:

Я ввел ваш пример в файл csv, затем ввел его с помощью read.csv и указал, что столбец 2 является символьным. Используя gsub, я заменяю букву c и открывающие и закрывающие круглые скобки. Затем я перебираю столбец 2, чтобы найти случаи, когда появляется запятая, и преобразовываю эти экземпляры в список целых чисел.

 data <- read.csv("SO question.csv", colClasses = c("character","character","integer"))

data$col2 <- gsub("(c|\(|\))","",data$col2)

for (i in 1:nrow(data)) {
  
  if (grepl(",", data$col2[i]) == TRUE) {
    
    temp <- unlist(strsplit(data$col2[i],","))
    data$col2[i] <- list(as.integer(temp))
    
  } 
}

data
 

Ответ №2:

Он выглядит как оба col2 и col3 имеет сложное содержимое. Предполагая, что возможное сложное содержимое c(...) и integer(0) мы заключаем оба в двойные кавычки и считываем их как символ, преобразующий из символа в список в последней строке. (Мы использовали литеральную строковую константу r'{…}’, введенную в R 4.0, чтобы избежать двойной обратной косой черты. Измените по мере необходимости, если вы используете более раннюю версию R.)

 library(dplyr)

DF <- "myfile.csv" %>%
  readLines %>%
  gsub(r'{(c(.*?)|integer(0))}', r'{"1"}', .) %>%
  read.csv(text = .) %>%
  mutate(across(2:3, ~ lapply(., function(x) eval(parse(text = x)))))
 

предоставление:

 > str(DF)
'data.frame':   3 obs. of  3 variables:
 $ col1: chr  "a" "c" "e"
 $ col2:List of 3
  ..$ : num 1
  ..$ : num  3 4
  ..$ : num 6
 $ col3:List of 3
  ..$ : int 
  ..$ : num 5
  ..$ : num 7
 

Примечание

Мы предполагаем, что файл выглядит так, как показано ниже:

 Lines <- ""col1","col2","col3"n"a",1,integer(0)n"c",c(3,4),5n"e",6,7n"
cat(Lines, file = "myfile.csv")
 

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

1. О! Я упростил это для примера. На самом деле существует ~ 20 столбцов с двумя внутренними (с известными позициями рядом друг с другом), которые могут содержать эти векторы. Это полезный метод, но он не совсем подходит для моих целей. Извините, что не упомянул эту необходимую деталь ранее!

2. ОК. Были пересмотрены с использованием модифицированного подхода.

3. Я полагаю read.csv(text = .) , что это сработало бы там, в этом нет необходимости, не так { read.csv(text = .) } ли?

4. Да, это правда. Удалили их.