R 当某些数字包含逗号作为千位分隔符时,如何读取数据?

R 当某些数字包含逗号作为千位分隔符时,如何读取数据?,r,csv,r-faq,R,Csv,R Faq,我有一个csv文件,其中一些数值表示为字符串,逗号为千位分隔符,例如“1513”而不是1513。将数据读入R的最简单方法是什么 我可以使用read.csv(…,colClasses=“character”),但在将这些列转换为数字之前,我必须从相关元素中去掉逗号,我找不到一个简洁的方法来实现这一点。不确定如何让read.csv正确解释它,但您可以使用gsub替换,”使用”,然后使用as.numeric将字符串转换为numeric: y <- c("1,200","20,000","100"

我有一个csv文件,其中一些数值表示为字符串,逗号为千位分隔符,例如
“1513”
而不是
1513
。将数据读入R的最简单方法是什么


我可以使用
read.csv(…,colClasses=“character”)
,但在将这些列转换为数字之前,我必须从相关元素中去掉逗号,我找不到一个简洁的方法来实现这一点。

不确定如何让
read.csv
正确解释它,但您可以使用
gsub
替换
,”
使用
,然后使用
as.numeric将字符串转换为
numeric

y <- c("1,200","20,000","100","12,111")
as.numeric(gsub(",", "", y))
# [1]  1200 20000 100 12111

y我认为预处理是最好的选择。您可以使用具有正则表达式替换选项的

例如,如果您的文件如下所示:

"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我想使用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))})
xR中的“预处理”:

知道逗号作为十进制分隔符可以由read.csv2(自动)或read.table(设置'dec'-参数)处理,这一点很有用,但与此问题没有直接关系

编辑:后来我通过设计一个新类发现了如何使用colClasses。见:


您可以让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'))
DF如果在调用
gsub时数字被“.”分隔,小数被“,”(1.200.000,00)您必须
将fixed=TRUE设置为.numeric(gsub(“.”,y,fixed=TRUE))
使用
mutate\u all
和管道的解决方案 假设你有以下几点:

> 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读入为 因素(默认)

mutate\u all
funs
中的函数应用于指定列

我按顺序执行,一次一个函数(如果使用多个函数)
funs中的函数
然后创建额外的、不必要的列)

这个问题已经问了好几年了,但我偶然发现了它,这意味着其他人可能会问

库/包有一些很好的特性。其中之一是一种很好的解释“凌乱”列的方法,如以下所示

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
的注释,要么在读取时必须进行处理。通常情况下,如果你试图在事后解决问题,会有一些很难找到的危险假设。(这就是为什么平面文件一开始是如此邪恶。)

例如,如果我没有标记
列类型
,我会得到以下结果:

> 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
字符
)而不是
数字

或者,更危险的是,如果它足够长,并且大多数早期元素不包含逗号:

> set.seed(1)
> tmp <- as.character(sample(c(1:10), 100, replace=TRUE))
> tmp <- c(tmp, "1,003")
> tmp <- paste(tmp, collapse="\"\n\"")
那你读那个逗号就麻烦了

> 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。以这里为例: 您可以按如下方式进行操作:

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 = ",")

txt使用read_delim函数,该函数是readr库的一部分,您可以指定其他参数:

locale = locale(decimal_mark = ",")

read_delim("filetoread.csv", ';", locale = locale(decimal_mark = ","))
*第二行中的分号表示read_delim将读取csv分号分隔的值

这将有助于读取所有带有逗号的数字作为正确的数字

问候


Mateusz Kania

我们也可以使用
readr::parse_number
,但列必须是字符。如果我们想将其应用于多个列,我们可以使用
lappy

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
数据

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)

df不是强制所有列都是char,在这种情况下,除了15:41之外的其他列也是char吗?也许让read.csv()决定,然后转换cols 15:41中的那些可能会得到“更多”数字列。是的,但正如我的问题所指出的,所有其他列都是字符。我可以用as.is=TRUE来代替,这会更一般。但是,通过使用默认的参数来决定读.cvs-(),因为它将把看起来像字符的任何东西转换成一个会导致数字列的麻烦的因素,因为它们不能正确地使用A.No.C.()。这是read.csv2的默认值,但逗号是硬连接到read.csv()中的。任何可以编写脚本的内容都应该使用逗号。手工操作会带来出错的机会,而且不易重复。这是一个非常好的技巧。它可以用于导入转换(例如,使用
setAs(“character”、“logical.Y.N”、函数(from)c(Y=TRUE,N=FALSE)[from])将Y/N值转换为逻辑向量。
)。要补充的是:您可以使用
setClass(“num.with.commas”)
suppresMessage(setAs(…)
来避免关于缺少类的消息。嗨,格雷格,感谢您分享这个便捷的功能。在执行时,我得到以下警告:在带有签名的“commare”、“character”、“num.with.commas”的“胁迫”方法中:类“num.with.commas”没有定义。知道这里的问题是什么吗,我有你的逐字逐句的代码?我查看了类似的问题链接,发现我需要设置类!谢谢你巧妙的把戏。谢谢,这是一个很好的观点
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
locale = locale(decimal_mark = ",")

read_delim("filetoread.csv", ';", locale = locale(decimal_mark = ","))
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
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)