R: почему, как избежать: read.table превращает символ (строки) в числовой, удаляя последний символ (двоеточие)

#r #dataframe #csv #import #export-to-csv

Вопрос:

У меня есть фрейм данных, который я хочу экспортировать в CSV и повторно импортировать в фрейм данных. При импорте один столбец поврежден-путем удаления двоеточия в конце строк и интерпретации их как числовых.

Вот минимальный пример:

 df <- data.frame(integers = c(1:8, NA, 10L),
                 doubles  = as.numeric(paste0(c(1:7, NA, 9, 10), ".1")),
                 strings = paste0(c(1:10),".")
                 )
df
str(df) # here the last column is "chr"

write.table(df,
            file = "df.csv",
            sep = "t",
            na = "NA",
            row.names = FALSE,
            col.names = TRUE,
            fileEncoding = "UTF-8",
)

df <- read.table(file = "df.csv",
                 header = TRUE,
                 sep = "t",
                 na.strings = "NA",
                 quote=""",
                 fileEncoding = "UTF-8"
                 )
df
str(df)  # here the last column is "num"
 

Ответ №1:

С read.table помощью , мы можем указать colClasses указанные в ?vector

Атомарные режимы являются «логическими», «целочисленными», «числовыми» (синоним «двойной»), «сложными», «символьными» и «необработанными».

Проблема в том, что ?read.table colClasses используется type.convert , если не указано, для автоматического определения типа столбца

Если не указано colClasses, все столбцы считываются как символьные столбцы, а затем преобразуются с помощью type.convert в логические, целочисленные, числовые, комплексные или (в зависимости от as.is) фактор в зависимости от обстоятельств.

Соответствующий код в read.table был бы

 ...
     do[1L] <- FALSE
    for (i in (1L:cols)[do]) {
        data[[i]] <- if (is.na(colClasses[i])) 
            type.convert(data[[i]], as.is = as.is[i], dec = dec, 
                numerals = numerals, na.strings = character(0L))
        else if (colClasses[i] == "factor") 
            as.factor(data[[i]])
        else if (colClasses[i] == "Date") 
            as.Date(data[[i]])
        else if (colClasses[i] == "POSIXct") 
            as.POSIXct(data[[i]])
        else methods::as(data[[i]], colClasses[i])
    }
...
 
 df <- read.table(file = "df.csv",
                 header = TRUE,
                 sep = "t",
                 na.strings = "NA",
                 quote=""",
                 fileEncoding = "UTF-8", 
           colClasses = c("integer", "numeric", "character")
                 )
 

-проверка стойки

 str(df)
'data.frame':   10 obs. of  3 variables:
 $ integers: int  1 2 3 4 5 6 7 8 NA 10
 $ doubles : num  1.1 2.1 3.1 4.1 5.1 6.1 7.1 NA 9.1 10.1
 $ strings : chr  "1." "2." "3." "4." ...
 

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

1. … Однако не странно ли, что он «удаляет» двоеточие и тем самым теряет единственный намек на то, что это может быть символьная строка? Если вы проверите df.csv вручную, вы увидите, что элементы последнего столбца заключены в кавычки.

2. @alex, где ты добавил двоеточие

3. @alex вы имели в виду c(1:10) , что это seq создание целого числа

4. Если вы возьмете текстовый редактор и откроете df.csv файл, вы увидите, что последний столбец имеет форму "x." (где x-число). Нахождение внутри кавычек должно быть разумным намеком для синтаксического анализатора НЕ преобразовывать (явные) строки внутри во что-то другое. Так почему же read.table вы игнорируете это?

5. Еще раз большое вам спасибо. Я уже принял ответ. Хорошего вам дня (-: