Làm thế nào để đọc dữ liệu khi một số số chứa dấu phẩy làm dấu phân cách hàng nghìn?


117

Tôi có một tệp csv trong đó một số giá trị số được biểu thị dưới dạng chuỗi với dấu phẩy là dấu phân cách nghìn, ví dụ: "1,513"thay vì 1513. Cách đơn giản nhất để đọc dữ liệu vào R là gì?

Tôi có thể sử dụng read.csv(..., colClasses="character"), nhưng sau đó tôi phải loại bỏ dấu phẩy khỏi các phần tử có liên quan trước khi chuyển đổi các cột đó thành số và tôi không thể tìm ra cách gọn gàng để làm điều đó.

Câu trả lời:


141

Không chắc chắn về cách read.csvdiễn giải nó đúng cách, nhưng bạn có thể sử dụng gsubđể thay thế ","bằng "", sau đó chuyển đổi chuỗi thành numericsử dụng as.numeric:

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

Điều này cũng đã được trả lời trước đây trên R-Help (và trong quý 2 tại đây ).

Ngoài ra, bạn có thể xử lý trước tệp, chẳng hạn như sedtrong unix.


60

Bạn có thể có read.table hoặc read.csv thực hiện chuyển đổi này cho bạn một cách bán tự động. Đầu tiên, hãy tạo một định nghĩa lớp mới, sau đó tạo một hàm chuyển đổi và đặt nó làm phương thức "as" bằng cách sử dụng hàm setAs như sau:

setClass("num.with.commas")
setAs("character", "num.with.commas", 
        function(from) as.numeric(gsub(",", "", from) ) )

Sau đó chạy read.csv như:

DF <- read.csv('your.file.here', 
   colClasses=c('num.with.commas','factor','character','numeric','num.with.commas'))

3
Đây là một thủ thuật rất hay. Nó có thể được sử dụng để chuyển đổi khi nhập (ví dụ: chuyển đổi giá trị Y / N thành vectơ logic bằng cách sử dụng setAs("character", "logical.Y.N", function(from) c(Y=TRUE,N=FALSE)[from] )).
Marek

1
Thủ thuật tương tự sử dụng trong vấn đề tương tự . Và để thêm: người ta có thể sử dụng một trong hai setClass("num.with.commas")hoặc suppresMessage(setAs(.....))để tránh thông báo về việc thiếu lớp.
Marek

Xin chào Greg, cảm ơn vì đã chia sẻ chức năng tiện dụng này. Khi thực hiện, tôi nhận được cảnh báo sau: trong phương thức cho 'ép buộc' với chữ ký '"ký tự", "num.with.commas"': không có định nghĩa cho lớp “num.with.commas” Mọi ý kiến ​​về vấn đề ở đây, Tôi có mã của bạn từng từ?
TheGoat 29/09/16

Tôi đã kiểm tra liên kết vấn đề tương tự và thấy rằng tôi cần thiết lập lớp! Cảm ơn vì thủ thuật gọn gàng.
TheGoat 29/09/16

17

Tôi muốn sử dụng R hơn là xử lý trước dữ liệu vì nó giúp dễ dàng hơn khi dữ liệu được sửa đổi. Theo gợi ý của Shane về việc sử dụng gsub, tôi nghĩ rằng điều này là gọn gàng nhất có thể của tôi:

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" không buộc tất cả các cột phải là char trong trường hợp đó những cột khác ngoài 15:41 cũng là char? Có thể để read.csv () quyết định và sau đó chuyển đổi các cột trong cols 15:41 có thể giúp bạn có thêm các cột số.
Dirk Eddelbuettel

Có, nhưng như câu hỏi của tôi đã lưu ý, tất cả các cột khác là ký tự. Thay vào đó, tôi có thể sử dụng as.is = TRUE sẽ tổng quát hơn. Nhưng để read.csv () quyết định bằng cách sử dụng các đối số mặc định là không hữu ích vì nó sẽ chuyển đổi bất kỳ thứ gì trông giống như một ký tự thành một yếu tố gây phức tạp cho các cột số vì sau đó chúng không chuyển đổi đúng cách sử dụng as.numeric () .
Rob Hyndman

Bạn nên cân nhắc đặt đối số dec = trong bảng đọc thành ".". Đó là mặc định cho read.csv2 nhưng dấu phẩy được viết cứng thành read.csv ().
IRTFM

15

Câu hỏi này đã có từ vài năm trước, nhưng tôi đã tình cờ gặp nó, có nghĩa là có thể những người khác sẽ làm.

Các readrthư viện / gói có một số tính năng tốt đẹp với nó. Một trong số đó là một cách hay để giải thích các cột "lộn xộn", như thế này.

library(readr)
read_csv("numbers\n800\n\"1,800\"\n\"3500\"\n6.5",
          col_types = list(col_numeric())
        )

Điều này mang lại

Nguồn: khung dữ liệu cục bộ [4 x 1]

  numbers
    (dbl)
1   800.0
2  1800.0
3  3500.0
4     6.5

Một điểm quan trọng khi đọc trong tệp: bạn phải xử lý trước, như nhận xét ở trên về sed hoặc bạn phải xử lý trong khi đọc . Thông thường, nếu bạn cố gắng sửa chữa mọi thứ sau thực tế, có một số giả định nguy hiểm được đặt ra rất khó tìm ra. (Đó là lý do tại sao các tập tin phẳng ngay từ đầu rất tệ.)

Ví dụ: nếu tôi không gắn cờ col_types , tôi sẽ nhận được điều này:

> 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

(Lưu ý rằng nó bây giờ là một chr ( character) thay vì a numeric.)

Hoặc, nguy hiểm hơn, nếu nó đủ dài và hầu hết các phần tử ban đầu không chứa dấu phẩy:

> set.seed(1)
> tmp <- as.character(sample(c(1:10), 100, replace=TRUE))
> tmp <- c(tmp, "1,003")
> tmp <- paste(tmp, collapse="\"\n\"")

(sao cho một số phần tử cuối cùng trông giống như vậy :)

\"5\"\n\"9\"\n\"7\"\n\"1,003"

Sau đó, bạn sẽ thấy khó khăn khi đọc dấu phẩy đó!

> 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. 

7

một dplyrgiải pháp sử dụngmutate_all và đường ống

nói rằng bạn có những thứ sau:

> 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

và muốn xóa dấu phẩy khỏi các biến năm X2014-X2016 và chuyển đổi chúng thành số. ngoài ra, giả sử X2014-X2016 được đọc dưới dạng các yếu tố (mặc định)

dft %>%
    mutate_all(funs(as.character(.)), X2014:X2016) %>%
    mutate_all(funs(gsub(",", "", .)), X2014:X2016) %>%
    mutate_all(funs(as.numeric(.)), X2014:X2016)

mutate_alláp dụng (các) hàm bên trong funscho các cột được chỉ định

Tôi đã thực hiện tuần tự, một hàm tại một thời điểm (nếu bạn sử dụng nhiều hàm bên trong funsthì bạn tạo thêm các cột không cần thiết)


3
mutate_eachkhông được dùng nữa. Bạn có muốn cập nhật câu trả lời của mình bằng mutate_athoặc tương tự không?
T_T

6

"Tiền xử lý" trong R:

lines <- "www, rrr, 1,234, ttt \n rrr,zzz, 1,234,567,987, rrr"

Có thể sử dụng readLinestrên a textConnection. Sau đó, chỉ xóa các dấu phẩy ở giữa các chữ số:

gsub("([0-9]+)\\,([0-9])", "\\1\\2", lines)

## [1] "www, rrr, 1234, ttt \n rrr,zzz, 1234567987, rrr"

Rất hữu ích khi biết nhưng không liên quan trực tiếp đến câu hỏi này rằng dấu phẩy làm dấu phân tách thập phân có thể được xử lý bởi read.csv2 (tự động) hoặc read.table (với cài đặt tham số 'dec').

Chỉnh sửa: Sau đó, tôi đã khám phá ra cách sử dụng colClasses bằng cách thiết kế một lớp mới. Xem:

Làm thế nào để tải df với dấu phân tách 1000 trong R dưới dạng lớp số?


Cảm ơn, đây là một con trỏ tốt nhưng nó không hoạt động với các chữ số chứa nhiều dấu thập phân, ví dụ: 1.234.567,89 - cần khắc phục sự cố này để nhập bảng tính google vào R, hãy xem stackoverflow.com/a/30020171/3096626 cho đơn giản hàm thực hiện công việc cho nhiều dấu thập phân
flexponsive

4

Nếu số được phân tách bằng "." và số thập phân bằng "," (1.200.000,00) khi gọi gsubbạn phảiset fixed=TRUE as.numeric(gsub(".","",y,fixed=TRUE))


3

Một cách rất tiện lợi là- readr::read_delimgia đình. Lấy ví dụ từ đây: Nhập csv có nhiều dấu phân cách vào R bạn có thể thực hiện như sau:

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

Kết quả nào dẫn đến kết quả mong đợi:

# 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

3

Sử dụng hàm read_delim, là một phần của thư viện readr , bạn có thể chỉ định tham số bổ sung:

locale = locale(decimal_mark = ",")

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

* Dấu chấm phẩy ở dòng thứ hai có nghĩa là read_delim sẽ đọc các giá trị được phân tách bằng dấu chấm phẩy csv.

Điều này sẽ giúp đọc tất cả các số có dấu phẩy là các số thích hợp.

Trân trọng

Mateusz Kania


3

Chúng ta cũng có thể sử dụng readr::parse_number, các cột phải là ký tự. Nếu chúng ta muốn áp dụng nó cho nhiều cột, chúng ta có thể lặp qua các cột bằng cách sử dụnglapply

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

Hoặc sử dụng mutate_atfrom dplyrđể áp dụng nó cho các biến cụ thể.

library(dplyr)
df %>% mutate_at(2:3, readr::parse_number)
#Or
df %>% mutate_at(vars(b:c), readr::parse_number)

dữ liệu

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)

1

Tôi nghĩ tiền xử lý là cách để đi. Bạn có thể sử dụng Notepad ++ có tùy chọn thay thế biểu thức chính quy.

Ví dụ: nếu tệp của bạn giống như sau:

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

Sau đó, bạn có thể sử dụng biểu thức chính quy "([0-9]+),([0-9]+)"và thay thế nó bằng\1\2

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

Sau đó, bạn có thể sử dụng x <- read.csv(file="x.csv",header=FALSE)để đọc tệp.


22
Bất cứ điều gì bạn có thể viết kịch bản, bạn nên làm. Làm điều đó bằng tay dẫn đến cơ hội cho lỗi, cũng như không thể tái tạo nhiều.
hadley
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.