我有一个 csv 文件,其中一些数值用字符串表示,逗号作为千分隔符,例如 "1,513"而不是 1513。将数据读入 R 的最简单方法是什么?
"1,513"
1513
我可以使用 read.csv(..., colClasses="character"),但是在将这些列转换为数字之前,我必须从相关元素中去掉逗号,而且我找不到一种简单的方法来做到这一点。
read.csv(..., colClasses="character")
不确定如何让 read.csv正确地解释它,但是您可以使用 gsub将 ","替换为 "",然后使用 as.numeric将字符串转换为 numeric:
read.csv
gsub
","
""
as.numeric
numeric
y <- c("1,200","20,000","100","12,111") as.numeric(gsub(",", "", y)) # [1] 1200 20000 100 12111
这是 前情提要(和在 这里是 Q2)。
或者,您可以对文件进行预处理,例如在 unix 中使用 sed。
sed
我认为预处理是可行的方法。你可以使用 记事本 + + ,它有一个正则表达式替换选项。
例如,如果你的文件是这样的:
"1,234","123","1,234" "234","123","1,234" 123,456,789
然后,可以使用正则表达式 "([0-9]+),([0-9]+)"并将其替换为 \1\2
"([0-9]+),([0-9]+)"
\1\2
1234,"123",1234 "234","123",1234 123,456,789
然后可以使用 x <- read.csv(file="x.csv",header=FALSE)读取文件。
x <- read.csv(file="x.csv",header=FALSE)
我想使用 R 而不是预处理的数据,因为它使它更容易当数据被修改。根据 Shane 关于使用 gsub的建议,我认为这是我能做的最简洁的事情了:
x <- read.csv("file.csv",header=TRUE,colClasses="character") col2cvt <- 15:41 x[,col2cvt] <- lapply(x[,col2cvt],function(x){as.numeric(gsub(",", "", x))})
R 中的“预处理”:
lines <- "www, rrr, 1,234, ttt \n rrr,zzz, 1,234,567,987, rrr"
可以在 textConnection上使用 readLines,然后只删除位于数字之间的逗号:
textConnection
readLines
gsub("([0-9]+)\\,([0-9])", "\\1\\2", lines) ## [1] "www, rrr, 1234, ttt \n rrr,zzz, 1234567987, rrr"
了解以逗号作为十进制分隔符可以由 read.csv2(自动)或 read.table (设置“ dec”参数)处理是非常有用的,但与这个问题没有直接关系。
编辑: 后来我通过设计一个新的类发现了如何使用 colClass。参见:
如何在 R 中加载带有1000个分隔符的 df 作为数值类?
您可以让 read.table 或 read.csv 半自动地为您执行此转换。首先创建一个新的类定义,然后创建一个转换函数,并使用 setAs 函数将其设置为“ as”方法,如下所示:
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'))
在调用 gsub时,如果数字由“ .”分隔,小数由“ ,”(1.200.000.00)分隔,则必须使用 set fixed=TRUE as.numeric(gsub(".","",y,fixed=TRUE))
set fixed=TRUE as.numeric(gsub(".","",y,fixed=TRUE))
mutate_all
dplyr
说你有以下资料:
> 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_all(funs(as.character(.)), X2014:X2016) %>% mutate_all(funs(gsub(",", "", .)), X2014:X2016) %>% mutate_all(funs(as.numeric(.)), X2014:X2016)
mutate_all将 funs中的函数应用于指定的列
funs
我是按顺序执行的,一次执行一个函数(如果使用多个 函数,然后创建额外的、不必要的列)
这个问题已经有好几年历史了,但我偶然发现了它,这意味着也许其他人也会这么做。
readr库/包有一些很好的特性。其中之一是一个很好的方式来解释“混乱”栏目,就像这些。
readr
library(readr) read_csv("numbers\n800\n\"1,800\"\n\"3500\"\n6.5", col_types = list(col_numeric()) )
这个产量
资料来源: 本地数据框架[4x1]
numbers (dbl) 1 800.0 2 1800.0 3 3500.0 4 6.5
读取文件时的一个重要问题是: 您要么必须预处理(如上面关于 sed的注释) ,要么必须处理 在看书的时候。通常情况下,如果你试图在事后解决问题,会有一些很难找到的危险假设。(这就是为什么平面文件从一开始就如此邪恶。)
例如,如果我没有标记 col_types,我会得到这个:
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。)
chr
character
或者,更危险的是,如果它足够长,而且大多数早期元素不包含逗号:
> 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::read_delim-family: 将带有多个分隔符的 csv 导入到 R 中,可以这样做:
readr::read_delim
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
使用 read _ delim 函数(它是 雷达库的一部分) ,您可以指定其他参数:
locale = locale(decimal_mark = ",") read_delim("filetoread.csv", ";", locale = locale(decimal_mark = ","))
* 第二行中的分号意味着 read _ delm 将读取以 csv 分号分隔的值。
这将有助于阅读所有逗号数字作为正确的数字。
问候
Mateusz Kania
我们也可以使用 readr::parse_number,但是列必须是字符。如果我们想对多个列应用它,我们可以使用 lapply循环遍历列
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
或者使用 dplyr中的 mutate_at将其应用于特定的变量。
mutate_at
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)