Как определить правильную кодировку для read.csv?

У меня есть этот файл (http://b7hq6v.alterupload.com/en/), который я хочу прочитать в R с помощью read.csv. Но я не могу определить правильную кодировку. Кажется, это что-то вроде UTF-8. Я использую R 2.12.1 на компьютере с WindowsXP. Любая помощь?


person Alex    schedule 26.01.2011    source источник


Ответы (6)


Прежде всего на основе более общего вопроса о StackOverflow невозможно определить кодировку файла со 100% уверенностью.

Я много раз боролся с этим и пришел к неавтоматическому решению:

Используйте iconvlist, чтобы получить все возможные кодировки:

codepages <- setNames(iconvlist(), iconvlist())

Затем прочитайте данные, используя каждый из них

x <- lapply(codepages, function(enc) try(read.table("encoding.asc",
                   fileEncoding=enc,
                   nrows=3, header=TRUE, sep="\t"))) # you get lots of errors/warning here

Здесь важно знать структуру файла (разделитель, заголовки). Установите кодировку, используя аргумент fileEncoding. Прочитано только несколько строк.
Теперь вы можете искать результаты:

unique(do.call(rbind, sapply(x, dim)))
#        [,1] [,2]
# 437       14    2
# CP1200     3   29
# CP12000    0    1

Похоже, правильный вариант с 3 строками и 29 столбцами, так что давайте посмотрим на них:

maybe_ok <- sapply(x, function(x) isTRUE(all.equal(dim(x), c(3,29))))
codepages[maybe_ok]
#    CP1200    UCS-2LE     UTF-16   UTF-16LE      UTF16    UTF16LE 
#  "CP1200"  "UCS-2LE"   "UTF-16" "UTF-16LE"    "UTF16"  "UTF16LE" 

Вы также можете посмотреть данные

x[maybe_ok]

Для вашего файла все эти кодировки возвращают идентичные данные (частично из-за некоторой избыточности, как вы видите).

Если вы не знаете специфику своего файла, вам нужно использовать readLines с некоторыми изменениями в рабочем процессе (например, вы не можете использовать fileEncoding, должны использовать length вместо dim, сделайте больше магии, чтобы найти правильные).

person Marek    schedule 27.01.2011
comment
Я сделал то же самое для iconvlist(), но с циклом. Решающим моментом было использование fileEncoding. Я неправильно использовал кодировку. Спасибо за вашу помощь. - person Alex; 27.01.2011
comment
Я набросал аналогичный подход на gist.github.com/837414 — я думаю, что более эффективно загружать данные один раз, а затем попробуйте разные кодировки, используя iconv. - person hadley; 22.11.2012
comment
@Марек Хороший трюк. По крайней мере, я знаю, что моя проблема read.csv не связана с fileEncoding. - person Tunn; 24.11.2016

Пакет readr, https://cran.r-project.org/web/packages/readr/readr.pdf включает функцию guess_encoding, которая вычисляет вероятность того, что файл будет закодирован в нескольких кодировках:

guess_encoding("your_file", n_max = 1000)
person Enrique Pérez Herrero    schedule 07.03.2016
comment
Этот вариант был очень красивым и простым в использовании. - person MadmanLee; 09.04.2019
comment
Однако иногда guess_encoding не дает определенных результатов. Пробовал на 11 CSV-файлах, и 2 из них были поровну разделены между несколькими кодировками. - person Dutschke; 13.08.2020

Во-первых, надо разобраться, что такое кодировка файла, что нельзя сделать в R (по крайней мере, насколько я знаю). Вы можете использовать для этого внешние инструменты, например. из Perl, Python или, например. утилита file под Linux/UNIX.

Как предложил @ssmit, у вас здесь кодировка UTF-16LE (Unicode), поэтому загрузите файл с этой кодировкой и используйте readLines, чтобы увидеть, что у вас есть в первых (например) 10 строках:

> f <- file('encoding.asc', open="r", encoding="UTF-16LE")   # UTF-16LE, which is "called" Unicode in Windows
> readLines(f,10)
 [1] "\tFe 2\tZn\tO\tC\tSi\tMn\tP\tS\tAl\tN\tCr\tNi\tMo\tCu\tV\tNb 2\tTi\tB\tZr\tCa\tH\tCo\tMg\tPb 2\tW\tCl\tNa 3\tAr"                                                                                                                          
 [2] ""                                                                                                                                                                                                                                         
 [3] "0\t0,003128\t3,82E-05\t0,0004196\t0\t0,001869\t0,005836\t0,004463\t0,002861\t0,02148\t0\t0,004768\t0,0003052\t0\t0,0037\t0,0391\t0,06409\t0,1157\t0,004654\t0\t0\t0\t0,00824\t7,63E-05\t0,003891\t0,004501\t0\t0,001335\t0,01175"         
 [4] "0,0005\t0,003265\t3,05E-05\t0,0003662\t0\t0,001709\t0,005798\t0,004395\t0,002808\t0,02155\t0\t0,004578\t0,0002441\t0\t0,003601\t0,03897\t0,06406\t0,1158\t0,0047\t0\t0\t0\t0,008026\t6,10E-05\t0,003876\t0,004425\t0\t0,001343\t0,01157"  
 [5] "0,001\t0,003332\t2,54E-05\t0,0003052\t0\t0,001704\t0,005671\t0,0044\t0,002823\t0,02164\t0\t0,004603\t0,0003306\t0\t0,003611\t0,03886\t0,06406\t0,1159\t0,004705\t0\t0\t0\t0,008036\t5,09E-05\t0,003815\t0,004501\t0\t0,001246\t0,01155"   
 [6] "0,0015\t0,003313\t2,18E-05\t0,0002616\t0\t0,001678\t0,005689\t0,004447\t0,002921\t0,02171\t0\t0,004621\t0,0003488\t0\t0,003597\t0,03889\t0,06404\t0,1158\t0,004752\t0\t0\t0\t0,008022\t4,36E-05\t0,003815\t0,004578\t0\t0,001264\t0,01144"
 [7] "0,002\t0,003313\t2,18E-05\t0,0002834\t0\t0,001591\t0,005646\t0,00436\t0,003008\t0,0218\t0\t0,004643\t0,0003488\t0\t0,003619\t0,03895\t0,06383\t0,1159\t0,004752\t0\t0\t0\t0,008\t4,36E-05\t0,003771\t0,004643\t0\t0,001351\t0,01142"      
 [8] "0,0025\t0,003488\t2,18E-05\t0,000218\t0\t0,001657\t0,00558\t0,004338\t0,002986\t0,02175\t0\t0,004469\t0,0002616\t0\t0,00351\t0,03889\t0,06374\t0,1159\t0,004621\t0\t0\t0\t0,008131\t4,36E-05\t0,003771\t0,004708\t0\t0,001243\t0,01125"   
 [9] "0,003\t0,003619\t0\t0,0001526\t0\t0,001591\t0,005668\t0,004207\t0,00303\t0,02169\t0\t0,00449\t0,0002834\t0\t0,00351\t0,03874\t0,06383\t0,116\t0,004665\t0\t0\t0\t0,007956\t0\t0,003749\t0,004796\t0\t0,001286\t0,01125"                   
[10] "0,0035\t0,003422\t0\t4,36E-05\t0\t0,001482\t0,005711\t0,004185\t0,003292\t0,02156\t0\t0,004665\t0,0003488\t0\t0,003553\t0,03852\t0,06391\t0,1158\t0,004708\t0\t0\t0\t0,007717\t0\t0,003597\t0,004905\t0\t0,00133\t0,01136"                   

Отсюда видно, что у нас есть заголовок, а во второй строке пустая строка (которая по умолчанию будет пропущена с помощью функции read.table), разделитель \t и десятичный символ ,.

> f <- file('encoding.asc', open="r", encoding="UTF-16LE")
> df <- read.table(f, sep='\t', dec=',', header=TRUE)

И посмотрим, что у нас есть:

> head(df)
       X     Fe.2       Zn         O C       Si       Mn        P        S
1 0.0000 0.003128 3.82e-05 0.0004196 0 0.001869 0.005836 0.004463 0.002861
2 0.0005 0.003265 3.05e-05 0.0003662 0 0.001709 0.005798 0.004395 0.002808
3 0.0010 0.003332 2.54e-05 0.0003052 0 0.001704 0.005671 0.004400 0.002823
4 0.0015 0.003313 2.18e-05 0.0002616 0 0.001678 0.005689 0.004447 0.002921
5 0.0020 0.003313 2.18e-05 0.0002834 0 0.001591 0.005646 0.004360 0.003008
6 0.0025 0.003488 2.18e-05 0.0002180 0 0.001657 0.005580 0.004338 0.002986
       Al N       Cr        Ni Mo       Cu       V    Nb.2     Ti        B Zr
1 0.02148 0 0.004768 0.0003052  0 0.003700 0.03910 0.06409 0.1157 0.004654  0
2 0.02155 0 0.004578 0.0002441  0 0.003601 0.03897 0.06406 0.1158 0.004700  0
3 0.02164 0 0.004603 0.0003306  0 0.003611 0.03886 0.06406 0.1159 0.004705  0
4 0.02171 0 0.004621 0.0003488  0 0.003597 0.03889 0.06404 0.1158 0.004752  0
5 0.02180 0 0.004643 0.0003488  0 0.003619 0.03895 0.06383 0.1159 0.004752  0
6 0.02175 0 0.004469 0.0002616  0 0.003510 0.03889 0.06374 0.1159 0.004621  0
  Ca H       Co       Mg     Pb.2        W Cl     Na.3      Ar
1  0 0 0.008240 7.63e-05 0.003891 0.004501  0 0.001335 0.01175
2  0 0 0.008026 6.10e-05 0.003876 0.004425  0 0.001343 0.01157
3  0 0 0.008036 5.09e-05 0.003815 0.004501  0 0.001246 0.01155
4  0 0 0.008022 4.36e-05 0.003815 0.004578  0 0.001264 0.01144
5  0 0 0.008000 4.36e-05 0.003771 0.004643  0 0.001351 0.01142
6  0 0 0.008131 4.36e-05 0.003771 0.004708  0 0.001243 0.01125
person daroczig    schedule 26.01.2011
comment
Спасибо, это работает. Но почему я должен пропустить первые 2 строки? И почему это не работает напрямую в read.csv? - person Alex; 27.01.2011
comment
@ user590885: вы правы, skip=2 можно опустить (я отредактировал свой ответ на основе этого), вторая пустая строка будет пропущена. Вы также можете использовать функцию read.csv для чтения этого файла (с теми же заданными параметрами), но, поскольку ваш файл разделен не запятыми, а табуляторами, я не думаю, что это было бы красиво. Ищите ?read.table для получения подробной информации о сходстве функций (различия можно найти в значениях по умолчанию). - person daroczig; 27.01.2011

Помимо использования пакета readr, вы также можете использовать stringi::stri_enc_detect2. Эта функция особенно эффективна, если известна локаль и если вы имеете дело с какой-либо формой UTF или ASCII: «... оказывается, что (эмпирически) stri_enc_detect2 работает лучше, чем на основе ICU [ stringi::stri_enc_detect используется guess_encoding], если предоставлен текст UTF-*."

Подробнее о stringi::stri_enc_detect.

Подробнее о stringi::stri_enc_detect2.

Запрос на изменение для предположения_кодирования

person ElToro1966    schedule 01.06.2018

Этот файл имеет кодировку UTF-16LE со спецификацией (знак порядка байтов). Вероятно, вам следует использовать encoding = "UTF-16LE"

person ssmir    schedule 26.01.2011
comment
Для полноты этого ответа: в read.table правильным параметром является fileEncoding. - person Marek; 27.01.2011

Мое аккуратное обновление решения @marek, так как я столкнулся с той же проблемой в 2020 году:

#Libraries
library(magrittr)
library(purrr)

#Make a vector of all the encodings supported by R
encodings <- set_names(iconvlist(), iconvlist())
#Make a simple reader function
reader <- function(encoding, file) {
  read.csv(file, fileEncoding = encoding, nrows = 3, header = TRUE)
}
#Create a "safe" version so we only get warnings, but errors don't stop it
# (May not always be necessary)
safe_reader <- safely(reader)

#Use the safe function with the encodings and the file being interrogated
map(encodings, safe_reader, `<TEST FILE LOCATION GOES HERE>`) %>%
  #Return just the results
  map("result") %>%
  #Keep only results that are dataframes
  keep(is.data.frame) %>%
  #Keep only results with more than one column
    #This predicate will need to change with the data
    #I knew this would work, because I could open in a text editor
  keep(~ ncol(.x) > 1) %>%
  #Return the names of the encodings
  names()
person Jason Mercer    schedule 31.01.2020