sqldf, csv и поля, содержащие запятые - PullRequest
3 голосов
/ 11 ноября 2011

Мне понадобилось время, чтобы понять это. Итак, я отвечаю на свой вопрос .

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

1001,     Amy,9:43:00, 99.2
1002,"Ben,Jr",9:43:00, 99.2
1003,"Ben,Sr",9:44:00, 99.3

Этот код работает только в * nix системах.

library(sqldf)
system("touch temp.csv")
system("echo '1001, Amy,9:43:00, 99.2\n1002,\"Ben,Jr\",9:43:00, 99.2\n1003,\"Ben,Sr\",9:44:00, 99.3' > temp.csv")

Если попытаться прочитать с

x <- read.csv.sql("temp.csv", header=FALSE)

Р жалуется

Error in try({ : 
  RS-DBI driver: (RS_sqlite_import: ./temp.csv line 2 expected 4 columns of data but found 5)

Решение sqldf - FAQ.13 также не работает:

x <- read.csv.sql("temp.csv", filter = "tr -d '\"' ", header=FALSE)

Опять R жалуется

Error in scan(file, what, nmax, sep, dec, quote, skip, nlines, na.strings,  : 
  line 1 did not have 5 elements

Фактически фильтр удаляет только двойные кавычки.

Итак, как поступить?

Ответы [ 2 ]

3 голосов
/ 11 ноября 2011

Perl и регулярные выражения для спасения.Копаясь в SO и играя с регулярными выражениями здесь , не сложно придумать правильный вариант:

 s/(\"[^\",]+),([^\"]+\")/$1_$2/g

, который соответствует "...,...", здесь точки совсем не двойныекавычки и запятые, и заменяет запятую подчеркиванием.Однострочный Perl - это правильный фильтр для передачи в sqldf:

x <- read.csv.sql("temp.csv", 
        filter = "perl -e 's/(\"[^\",]+)_([^\"]+\")/$1_$2/g'", 
        header=FALSE)

Вот кадр данных x

> x
    V1       V2      V3   V4
1 1001      Amy 9:43:00 99.2
2 1002 "Ben_Jr" 9:43:00 99.2
3 1003 "Ben_Sr" 9:44:00 99.3

Теперь космодез DYO для строк ...

РЕДАКТИРОВАТЬ : приведенное выше регулярное выражение заменяет только первое вхождение запятой в поле.Для замены всех случаев используйте это

s{(\"[^\",]+),([^\"]+\")}{$_= $&, s/,/_/g, $_}eg

Что отличается?

  1. Я заменил разделители / на {};
  2. Опция e в самом конце указывает синтаксическому анализатору интерпретировать поле замены как код perl;
  3. Повторение - это простая замена регулярного выражения, которая заменяет все "," на "_" в соответствующей подстроке $&.

Пример:

system("touch temp.csv")
system("echo '1001, Amy,9:43:00, 99.2\n1002,\"Ben,Jr,More,Commas\",9:43:00, 99.2\n1003,\"Ben,Sr\",9:44:00, 99.3' > temp.csv")

Файл temp.csv выглядит так:

1001,                 Amy,9:43:00, 99.2
1002,"Ben,Jr,More,Commas",9:43:00, 99.2
1003,            "Ben,Sr",9:44:00, 99.3

И может быть прочитан с помощью

x <- read.csv.sql("temp.csv", 
       filter = "perl -p -e 's{(\"[^\",]+),([^\"]+\")}{$_= $&, s/,/_/g, $_}eg'", 
       header=FALSE)
> x
    V1                   V2      V3   V4
1 1001                  Amy 9:43:00 99.2
2 1002 "Ben_Jr_More_Commas" 9:43:00 99.2
3 1003             "Ben_Sr" 9:44:00 99.3
0 голосов
/ 19 июня 2015

Для Windows sqldf теперь поставляется с trcomma2dot.vbs , который делает это по умолчанию с read.csv2.sql.Хотя он обнаружил, что он очень медленный для очень больших данных. (> 1 млн. Строк)

В нем упоминается "tr" для систем, не основанных на Windows, но я не смог попробовать.

...