R: read.table интерпретирует \ r как новую строку

Резюме

Я пытаюсь читать данные твиттера с помощью read.table. Но у меня есть строки, оканчивающиеся только на \r, что вызывает проблемы, поэтому я хотел бы пропустить некоторые строки.

Формат данных

Данные представлены в формате CSV, разделенном табуляцией, и имеют следующую форму:

id \t userid \t date \t latitude \t longitude \t location \t tweet \r\n

(Примечание: я добавил пробелы для удобства чтения, а \t, \r и \n соответствуют ожидаемым TAB, CR и LF)

Вот несколько примеров:

488397447040086017  1220042672  20140713190000  -22.923528  -43.238966  Rio de Janeiro, Rio de Janeiro  os moradores da minha rua devem me odiar
488397446960381952  1960969112  20140713190000  60.998575   68.998468   Ханты-Мансийск, Ханты-Мансийск  Вот интересом, мне одной пофиг на футбол?
488397446997762049  1449959828  20140713190000  32.777693   -97.307257  Fort Worth, TX  Buena suerte Argentina

Чтение данных

Были некоторые проблемы (# как комментарии, ' как символ кавычки, кодировка, ...), которые я уже частично решил:

readTweets <- function(fileName) {
  # read tweets from file
  tweets <- read.table(fileName, sep = "\t", quote = "", comment.char = "",
                       col.names = c("id", "user", "date", "latitude", 
                                     "longitude", "location", "tweet"),
                       colClasses = c("numeric", "numeric", "character",
                                      "double", "double", "character",
                                      "character"), encoding = "utf8")

  tweets
}

Как вы можете легко видеть, я также добавил параметр colClasses, чтобы дать полям некоторые полезные типы (я также изменил столбец даты на POSIXct, но мне нужно выполнить форматирование самостоятельно - побочный квест: есть ли способ применить функции к импортированным столбцам автоматически?).

Ошибка

Это сработало на небольшом тестовом наборе, подобном приведенному выше. Однако, когда я попытался загрузить больший набор данных, я получил следующую ошибку:

Error in scan(file, what, nmax, sep, dec, quote, skip, nlines, na.strings,  : 
  scan() expected 'a real', got '(:'

Небольшой поиск в файле показывает следующую запись:

488397464438071297  403662206   20140713190004  19.320504   -76.426316      @Toneishe_Lovee @purifiedhoran 
(:

Похоже, что новая строка находится не в том месте! Сейчас это огромная проблема, как я могу сказать, что строка - это новая строка или нет? А почему так? Я решил взглянуть более подробно и выяснил (снова добавлены пробелы, теперь вы понимаете, почему я опубликовал формат точнее), используя опцию Показать все символы в Notepad ++, как на самом деле выглядит запись:

488397464438071297 \t 403662206 \t 20140713190004 \t 19.320504 \t -76.426316 \t @Toneishe_Lovee @purifiedhoran \r (: \r\n

Обратите внимание на CR перед смайликом.

Простое решение

Я каким-то образом решил эту проблему, прочитав первый столбец как символы, заполнив строки и установив пустые поля на NA, а затем используя complete.cases:

readTweets <- function(fileName) {
  # read tweets from file
  tweets <- read.table(fileName, sep = "\t", quote = "", comment.char = "",
                       col.names = c("id", "user", "date", "latitude", 
                                     "longitude", "location", "tweet"),
                       colClasses = c("character", "numeric", "character",
                                      "double", "double", "character",
                                      "character"), encoding = "utf8",
                       fill = TRUE, na.strings = TRUE)
  # remove incorrect rows and convert id to numeric
  tweets      <- tweets[complete.cases(tweets[,c("id", "user", "date")]),]
  tweets$id   <- as.numeric(tweets$id)
  rownames(tweets) <- NULL
  tweets
}

Я все еще задаюсь вопросом, можно ли вообще вводить CR в твиттер или человек, который дал мне файлы csv, просто испортил формат.

Профессиональное решение

Можно ли пропустить неполные строки (без повторной обработки всех данных), чтобы я мог напрямую использовать числовое значение colClass для идентификатора?

ОС / Файл / и т. Д.

В соответствии с просьбой в комментариях, здесь есть дополнительная техническая информация:

  • Платформа $: x86_64-w64-mingw32
  • $ system: x86_64, mingw32
  • $ svn rev: 66115
  • $ version.string: R версия 3.1.1 (10.07.2014)
  • ОС: Windows 8 (я не ожидал, что R будет работать с моей установкой mingw)

Пример файла:

  • Загрузить, 788 B, csv (разделены табуляцией), содержит 5 твитов, включая ошибочный (секунда)
  • Формат файла - UTF-8 без спецификации, Notepad ++ определяет окончания строк как Dos \ Windows

person Sebastian Höffner    schedule 20.10.2014    source источник
comment
Без образца файла, с которым можно было бы поиграть, сложно создать образец с теми же байтами, которые принадлежат вам, чтобы проводить какое-либо тестирование. Кроме того, какая версия ОС и R используется в качестве перевода строки, зависит от ОС.   -  person MrFlick    schedule 20.10.2014
comment
Куда лучше всего загружать файлы для переполнения стека, чтобы они были доступны для поколений? Я использую Windows, но сам файл не должен отличаться от ОС к ОС. R - это версия 3.1.1. Добавлю информацию к вопросу.   -  person Sebastian Höffner    schedule 20.10.2014


Ответы (1)


Поскольку R работает в нескольких ОС, а в разных ОС используются разные окончания строк, может быть довольно сложно точно контролировать, что именно используется в качестве окончания строки, которое будет работать во всех ОС. Самый простой способ исправить это - заключить столбец твита в кавычки. Если у вас есть поля в кавычках, разрешены встроенные переводы строки. В противном случае вы можете манипулировать байтами с помощью регулярных выражений и тому подобного. Все зависит от того, что вы собираетесь делать со встроенными символами новой строки. Не уверен, хотите вы их сохранить или нет.

Вот дамп вашего образца файла

ctx <- "488397464357974017\t2168124983\t20140713190004\t24.584653\t46.540044\tالرياض, المملكة العربية السعودية\tأتوقع البطولة أرجنتينية ، من بداية البطولة كل الظروف والعوامل تريد الأرجنتين ..\r\n488397464438071297\t403662206\t20140713190004\t19.320504\t-76.426316\t\t@Toneishe_Lovee @purifiedhoran \r(:\r\n488397464442265600\t2510306157\t20140713190004\t36.517741\t-5.317234\tGaucín, Málaga\t#AlemaniaArgentina Vamos #GER\r\n488397464584871936\t539048975\t20140713190004\t42.550627\t9.440454\tLucciana, Haute-Corse\ton a tous le seum contre Pauline 4/5 mais dsl zayn l'a pas unfollow , ça fait 5 mois que vous sortez ça \U0001f615\r\n488397463997276160\t194876164\t20140713190004\t37.724866\t-120.93389\tRiverbank, CA\t@AlexxisAvila Shhh! Lol\r\n"

Мы можем разбить его на матрицу символов с помощью

mm <- do.call(rbind, strsplit(strsplit(ctx, "\r\n")[[1]], "\t"))

Затем мы можем преобразовать в data.frame

dd<-data.frame(mm, stringsAsFactors=F)
dd[,c(1,2,4,5)]<-lapply(dd[,c(1,2,4,5)], as.numeric)

затем, если вы запишете это в файл (и разрешите цитировать значения символов)

write.table(dd, "tweets2.csv", row.names=F, col.names=F, sep="\t")

Вы можете прочитать это без проблем с

dd2 <- read.table("tweets2.csv", sep = "\t", comment.char = "",
    col.names = c("id", "user", "date", "latitude", 
        "longitude", "location", "tweet"),
    colClasses = c("character", "numeric", "character",
        "double", "double", "character",
         "character"),
    encoding = "utf8")

Так что, если бы файл пришел к вам с кавычками в последней колонке, было бы намного проще импортировать его.

И если вы хотите прочитать файл в виде одной большой символьной строки, как я сделал для создания ctx, вы можете сделать это с помощью

ctx <- readChar(fileName, file.info(fileName)$size)

что может быть полезно, если вы хотите сначала проделать еще одну манипуляцию. Например, вы можете удалить значения \r, за которыми не следует \n. Вы могли бы сделать что с

gsub("\\r(?!\\n)","[nl]", ctx, perl=T)

и я думаю, вы можете прочитать это прямо в read.table

read.table(text=gsub("\\r(?!\\n)","[nl]", ctx, perl=T), sep="\t")

(Я тестирую Mac, который использует разные окончания строк, поэтому он не работает, но может быть в Windows).

person MrFlick    schedule 20.10.2014
comment
Я до сих пор не понимаю, чем могут отличаться окончания строк для одного и того же файла: у меня много файлов, которые заканчиваются только LF и поэтому не отображаются правильно в редакторе Windows. Однако блокнот ++ всегда показывает правильные окончания строки. В любом случае ваш readChar в сочетании с gsub неплохо справился с задачей (хотя я изменил регулярное выражение на \\r(?!\\n), что, как мне кажется, легче интерпретировать) и мне очень помогает. Спасибо! - person Sebastian Höffner; 21.10.2014
comment
Я не думаю, что окончания строк в файле разные, я просто думаю, что столбец твита имеет встроенный \r. У вас могут быть новые строчки в твитах, чтобы это выглядело полностью обоснованным. Да, эту версию регулярного выражения легче читать. Я думал, что пробовал это на своем Mac, но это не сработало; однако при повторном тестировании кажется, что все работает нормально. Я обновлю ответ. - person MrFlick; 21.10.2014