#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. Да, это правда. Удалили их.