Как читать данные, когда некоторые числа содержат запятые в качестве разделителя тысяч?
У меня есть CSV-файл, где некоторые числовые значения выражаются в виде строк с запятыми в качестве разделителя тысяч, например "1,513"
вместо 1513
, Какой самый простой способ прочитать данные в R?
я могу использовать read.csv(..., colClasses="character")
, но затем я должен вычеркнуть запятые из соответствующих элементов перед преобразованием этих столбцов в числовые, и я не могу найти изящный способ сделать это.
12 ответов
Я хочу использовать R, а не предварительную обработку данных, так как это облегчает пересмотр данных. Следуя предложению Шейна об использовании gsub
Я думаю, что это настолько аккуратно, насколько я могу сделать:
x <- read.csv("file.csv",header=TRUE,colClasses="character")
col2cvt <- 15:41
x[,col2cvt] <- lapply(x[,col2cvt],function(x){as.numeric(gsub(",", "", x))})
Не уверен насчет того, как иметь read.csv
интерпретировать это правильно, но вы можете использовать gsub
заменить ","
с ""
, а затем преобразовать строку в numeric
с помощью as.numeric
:
y <- c("1,200","20,000","100","12,111")
as.numeric(gsub(",", "", y))
# [1] 1200 20000 100 12111
На этот вопрос также ответили ранее в R-Help (и в Q2 здесь).
Кроме того, вы можете предварительно обработать файл, например, с помощью sed
в Unix.
Вы можете сделать read.table или read.csv сделать это преобразование для вас полуавтоматически. Сначала создайте новое определение класса, затем создайте функцию преобразования и установите его как метод "as", используя функцию setAs следующим образом:
setClass("num.with.commas")
setAs("character", "num.with.commas",
function(from) as.numeric(gsub(",", "", from) ) )
Затем запустите read.csv как:
DF <- read.csv('your.file.here',
colClasses=c('num.with.commas','factor','character','numeric','num.with.commas'))
Этому вопросу уже несколько лет, но я наткнулся на него, а значит, может быть, и другие.
readr
библиотека / пакет имеет некоторые приятные особенности. Один из них - хороший способ интерпретировать "грязные" столбцы, подобные этим.
library(readr)
read_csv("numbers\n800\n\"1,800\"\n\"3500\"\n6.5",
col_types = list(col_numeric())
)
Это дает
Источник: локальный фрейм данных [4 x 1]
numbers
(dbl)
1 800.0
2 1800.0
3 3500.0
4 6.5
Важный момент при чтении в файлах: вы должны либо предварительно обработать, как в комментарии выше относительно sed
или вы должны обрабатывать во время чтения. Часто, если вы пытаетесь исправить ситуацию после факта, есть некоторые опасные предположения, которые трудно найти. (Именно поэтому плоские файлы так злы.)
Например, если бы я не пометил col_types
Я бы получил это:
> read_csv("numbers\n800\n\"1,800\"\n\"3500\"\n6.5")
Source: local data frame [4 x 1]
numbers
(chr)
1 800
2 1,800
3 3500
4 6.5
(Обратите внимание, что теперь это chr
(character
) вместо numeric
.)
Или, что более опасно, если бы он был достаточно длинным и большинство ранних элементов не содержало запятых:
> set.seed(1)
> tmp <- as.character(sample(c(1:10), 100, replace=TRUE))
> tmp <- c(tmp, "1,003")
> tmp <- paste(tmp, collapse="\"\n\"")
(так, что последние несколько элементов выглядят как:)
\"5\"\n\"9\"\n\"7\"\n\"1,003"
Тогда вам будет трудно читать эту запятую!
> tail(read_csv(tmp))
Source: local data frame [6 x 1]
3"
(dbl)
1 8.000
2 5.000
3 5.000
4 9.000
5 7.000
6 1.003
Warning message:
1 problems parsing literal data. See problems(...) for more details.
Мы также можем использовать readr::parse_number
, однако столбцы должны быть символами. Если мы хотим применить его для нескольких столбцов, мы можем перебирать столбцы, используяlapply
df[2:3] <- lapply(df[2:3], readr::parse_number)
df
# a b c
#1 a 12234 12
#2 b 123 1234123
#3 c 1234 1234
#4 d 13456234 15342
#5 e 12312 12334512
Или используйте mutate_at
из dplyr
применить его к конкретным переменным.
library(dplyr)
df %>% mutate_at(2:3, readr::parse_number)
#Or
df %>% mutate_at(vars(b:c), readr::parse_number)
данные
df <- data.frame(a = letters[1:5],
b = c("12,234", "123", "1,234", "13,456,234", "123,12"),
c = c("12", "1,234,123","1234", "15,342", "123,345,12"),
stringsAsFactors = FALSE)
dplyr
решение с использованием mutate_each
и трубы
скажем, у вас есть следующее:
> dft
Source: local data frame [11 x 5]
Bureau.Name Account.Code X2014 X2015 X2016
1 Senate 110 158,000 211,000 186,000
2 Senate 115 0 0 0
3 Senate 123 15,000 71,000 21,000
4 Senate 126 6,000 14,000 8,000
5 Senate 127 110,000 234,000 134,000
6 Senate 128 120,000 159,000 134,000
7 Senate 129 0 0 0
8 Senate 130 368,000 465,000 441,000
9 Senate 132 0 0 0
10 Senate 140 0 0 0
11 Senate 140 0 0 0
и хотите удалить запятые из переменных года X2014-X2016 и преобразовать их в числовые. также, скажем, X2014-X2016 читаются как факторы (по умолчанию)
dft %>%
mutate_each(funs(as.character(.)), X2014:X2016) %>%
mutate_each(funs(gsub(",", "", .)), X2014:X2016) %>%
mutate_each(funs(as.numeric(.)), X2014:X2016)
mutate_each
применяет функцию (и) внутри funs
в указанные столбцы
Я сделал это последовательно, по одной функции за раз (если вы используете несколько функций внутри funs
затем вы создаете дополнительные, ненужные столбцы)
Используя функцию read_delim, которая является частью библиотеки readr, вы можете указать дополнительный параметр:
locale = locale(decimal_mark = ",")
read_delim("filetoread.csv", ';", locale = locale(decimal_mark = ","))
* Точка с запятой во второй строке означает, что read_delim будет читать значения, разделенные точкой с запятой в формате csv.
Это поможет прочитать все числа с запятой как правильные числа.
С уважением
Матеуш Кания
"Препроцесс" в R:
lines <- "www, rrr, 1,234, ttt \n rrr,zzz, 1,234,567,987, rrr"
Можешь использовать readLines
на textConnection
, Затем удалите только запятые между цифрами:
gsub("([0-9]+)\\,([0-9])", "\\1\\2", lines)
## [1] "www, rrr, 1234, ttt \n rrr,zzz, 1234567987, rrr"
Также полезно знать, но не иметь прямого отношения к этому вопросу, что запятые как десятичные разделители могут быть обработаны read.csv2 (автоматически) или read.table(с установкой параметра 'dec').
Изменить: Позже я узнал, как использовать colClasses при разработке нового класса. Увидеть:
Как загрузить df с разделителем 1000 в R как числовой класс?
Если число отделено "." и десятичные дроби "," (1.200.000,00) в вызове gsub
Вы должны set fixed=TRUE as.numeric(gsub(".","",y,fixed=TRUE))
Очень удобный способ readr::read_delim
-семейством. Взяв пример отсюда: импортируя csv с несколькими разделителями в R, вы можете сделать это следующим образом:
txt <- 'OBJECTID,District_N,ZONE_CODE,COUNT,AREA,SUM
1,Bagamoyo,1,"136,227","8,514,187,500.000000000000000","352,678.813105723350000"
2,Bariadi,2,"88,350","5,521,875,000.000000000000000","526,307.288878142830000"
3,Chunya,3,"483,059","30,191,187,500.000000000000000","352,444.699742995200000"'
require(readr)
read_csv(txt) # = read_delim(txt, delim = ",")
Что приводит к ожидаемому результату:
# A tibble: 3 × 6
OBJECTID District_N ZONE_CODE COUNT AREA SUM
<int> <chr> <int> <dbl> <dbl> <dbl>
1 1 Bagamoyo 1 136227 8514187500 352678.8
2 2 Bariadi 2 88350 5521875000 526307.3
3 3 Chunya 3 483059 30191187500 352444.7
Я думаю, что предварительная обработка - путь. Вы можете использовать Notepad++, у которого есть опция замены регулярного выражения.
Например, если ваш файл был таким:
"1,234","123","1,234"
"234","123","1,234"
123,456,789
Затем вы можете использовать регулярное выражение "([0-9]+),([0-9]+)"
и заменить его на \1\2
1234,"123",1234
"234","123",1234
123,456,789
Тогда вы могли бы использовать x <- read.csv(file="x.csv",header=FALSE)
прочитать файл.
Другое решение:
y <- c("1,200","20,000","100","12,111")
as.numeric(unlist(lapply( strsplit(y,","),paste, collapse="")))
Это будет значительно медленнее, чем gsub
,хоть.
Это не так сложно, попробуйте это: y<- as.numeric (gsub (",", "", as.character (y))), и если это только один из столбцов, вы можете задать для него y $ 2 как показано y $ 2 <- as.numeric (gsub (",", "", as.character (y $ 2)))