我有一个csv文件,其中一些数字值表示为字符串,并用逗号作为千位分隔符,例如用"1,513"代替1513。将数据读入R的最简单方法是什么?

我可以使用read.csv(..., colClasses="character"),但是在将这些列转换为数值之前,我必须从相关元素中去除逗号,但是我不能找到一种整洁的方法。

#1 楼

不确定如何正确解释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中得到回答)。

或者,您可以预处理文件,例如,在unix中使用sed

#2 楼

您可以让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'))


评论


这是非常好的技巧。它可以用于导入时转换(例如,使用setAs(“ character”,“ logical.YN”,function(from)c(Y = TRUE,N = FALSE)[from]将Y / N值转换为逻辑向量))。

–马雷克
2010年9月1日8:49

在类似问题中使用相同的技巧。并且要补充一点:可以使用setClass(“ num.with.commas”)或suppresMessage(setAs(.....))来避免有关缺少类的消息。

–马雷克
2011年5月10日13:12



嗨,格雷格,感谢您分享此便捷功能。执行后,我将收到以下警告:在带有符号“字符”,“ num.with.commas”的“强制”方法中:类“ num.with.commas”没有定义任何想法在这里,我有你的代码一个字一个字吗?

–TheGoat
16-09-29在22:18

我检查了类似的问题链接,发现需要设置课程!感谢您的巧妙技巧。

–TheGoat
16-9-29在22:54

#3 楼

我想使用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))})


评论


colClasses =“ char”不会强制所有列为char,在这种情况下,除15:41以外的其他列也为char?也许让read.csv()决定然后将其转换为cols 15:41中的内容,可能会为您提供更多的数字列。

–德克·埃德尔布特尔
09-10-6在11:40

是的,但是正如我的问题所指出的,其他所有列都是字符。我可以使用as.is = TRUE代替,它将更通用。但是让read.csv()通过使用默认参数来决定是没有帮助的,因为它将将看起来像字符的任何内容转换为一个导致数字列麻烦的因素,因为这样它们就不能使用as.numeric()正确地进行转换。

– Rob Hyndman
09年10月6日在22:18

您应该考虑将读取表中的dec =参数设置为“。”。这是read.csv2的默认设置,但逗号硬连接到read.csv()中。

– IRTFM
2011年1月30日23:15

#4 楼

这个问题已有好几年了,但是我偶然发现了它,这意味着也许其他人也会这样做。

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


(请注意,现在它是一个chrcharacter),而不是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. 


#5 楼

使用dplyr和管道的mutate_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是作为
因子(默认值)读取的。

br />
我是依次执行的,一次只执行一个函数(如果在mutate_all中使用多个
函数,则会创建其他不必要的列)

评论


mutate_each已弃用。您要使用mutate_at或类似名称更新答案吗?

– T_T
18-2-15在23:07

#6 楼

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"


知道但与该问题没有直接关系的是,逗号可以作为小数点分隔符来读取,这与它没有直接关系。 csv2(自动)或read.table(带有'dec'参数的设置)。

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

如何在R中将带有1000个分隔符的df加载为数字类?

评论


谢谢,这是一个很好的指针,但不适用于包含多个小数点的数字,例如1,234,567.89-需要解决此问题,才能将Google电子表格导入R,请参见stackoverflow.com/a/30020171/3096626,了解一个简单的函数,该函数可以处理多个小数点

–灵活
2015年5月3日22:46

#7 楼

我们也可以使用readr::parse_number,但列必须是字符。如果要将其应用于多列,可以使用lapply
循环遍历各列,也可以使用mutate_at中的dplyr将其应用于特定变量。

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)


#8 楼

如果数字用“。”分隔。和在调用gsub时用“,”(1.200.000,00)十进制表示,您必须set fixed=TRUE as.numeric(gsub(".","",y,fixed=TRUE))

#9 楼

一个非常方便的方法是readr::read_delim -family。从此处获取示例:
将具有多个分隔符的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


#10 楼

使用readr库中的read_delim函数,可以指定其他参数:

locale = locale(decimal_mark = ",")

read_delim("filetoread.csv", ';", locale = locale(decimal_mark = ","))


*第二行中的分号表示read_delim将读取csv分号分隔的值。 br />
这将有助于读取所有带逗号的数字作为正确的数字。

注意事项

Mateusz Kania

#11 楼

我认为预处理是要走的路。您可以使用具有正则表达式替换选项的Notepad ++。

例如,如果您的文件是这样的:

"1,234","123","1,234"
"234","123","1,234"
123,456,789


然后,您可以使用正则表达式"([0-9]+),([0-9]+)"并将其替换为

1234,"123",1234
"234","123",1234
123,456,789


然后可以使用x <- read.csv(file="x.csv",header=FALSE)读取文件。

评论


您应该编写的任何脚本。手动执行操作会带来出错的机会,而且再现性很差。

–哈德利
09-10-7 13:38