Як читати дані, коли деякі числа містять коми як роздільник тисяч?


117

У мене є файл csv, де деякі числові значення виражаються у вигляді рядків із комами як роздільник тисяч, наприклад "1,513"замість 1513. Який найпростіший спосіб зчитувати дані в R?

Я можу використовувати read.csv(..., colClasses="character"), але тоді мені доведеться викреслити коми з відповідних елементів, перш ніж перетворити ці стовпці в числові, і я не можу знайти акуратний спосіб це зробити.

Відповіді:


141

Не впевнений , що про те , щоб 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 (і в другому кварталі тут ).

Крім того, ви можете попередньо обробити файл, наприклад, sedв unix.


60

Ви можете прочитати таблицю чи read.csv зробити це перетворення для вас напівавтоматично. Спочатку створіть нове визначення класу, потім створіть функцію перетворення та встановіть її як метод "як", використовуючи функцію 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'))

3
Це дуже приємна хитрість. Він може бути використаний для перетворення під час імпорту (наприклад, перетворення значень Y / N в логічний вектор за допомогою setAs("character", "logical.Y.N", function(from) c(Y=TRUE,N=FALSE)[from] )).
Марек

1
Цей же трюк використовують у подібній проблемі . І додати: можна використовувати setClass("num.with.commas")або suppresMessage(setAs(.....))уникати повідомлення про відсутність класу.
Марек

Привіт Грег, дякую за те, що поділився цією зручною функцією. Після виконання я отримую таке попередження: у методі 'примушування' з підписом "" символ "," num.with.commas "': немає визначення для класу" num.with.commas "Будь-яке уявлення про те, що тут проблема, У вас є ваше кодове слово за словом?
TheGoat

Я перевірив аналогічне посилання проблеми і побачив, що мені потрібно встановити клас! Дякую за акуратну хитрість.
TheGoat

17

Я хочу використовувати 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))})

Чи не colClasses = "char" примушує усі стовпці бути char, і в цьому випадку інші, крім 15:41, також є char Можливо, якщо дозволити read.csv () вирішити, а потім перетворити ті, які в cols 15:41 можуть отримати "більше" числових стовпців.
Дірк Еддельбюттель

Так, але, як моє запитання зазначалося, усі інші стовпці мають характер. Я міг би використовувати натомість as.is = TRUE, що було б більш загальним. Але дозволяти read.csv () приймати рішення за допомогою аргументів за замовчуванням не є корисним, оскільки воно перетворить все, що схоже на символ, у фактор, який спричиняє клопоти для числових стовпців, оскільки тоді вони не конвертують належним чином, використовуючи as.numeric () .
Роб Хайндман

Вам слід розглянути можливість встановлення аргументу dec = в таблиці читання на ".". Це за замовчуванням для read.csv2, але кома вбудована в read.csv ().
IRTFM

15

Це питання вже кілька років, але я натрапив на нього, а це означає, що, можливо, інші.

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. 

7

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 читаються як фактори (за замовчуванням)

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то створюєте додаткові, непотрібні стовпці)


3
mutate_eachзастаріло. Ви хочете оновити свою відповідь mutate_atчи подібне?
T_T

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"

Це питання корисно знати, але не має безпосереднього відношення до цього питання про те, що комами як десятковими роздільниками можна керувати read.csv2 (автоматично) або read.table (із встановленням параметра 'dec').

Редагувати: Пізніше я з’ясував, як використовувати colClasses, створивши новий клас. Побачити:

Як завантажити df з роздільником 1000 в R як числовий клас?


Дякую, це був хороший вказівник, але він не працює для цифр, які містять кілька десяткових знаків, наприклад, 1,234,567.89 - потрібні для вирішення цієї проблеми для імпорту електронної таблиці Google в R, див. Stackoverflow.com/a/30020171/3096626 для простого функція, яка виконує завдання для кількох десяткових знаків
flexponsive

4

Якщо число відокремлено "". і десяткові знаки за допомогою "," (1.200.000,00) при виклику gsubви повинніset fixed=TRUE as.numeric(gsub(".","",y,fixed=TRUE))


3

Дуже зручний спосіб - 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

3

За допомогою функції read_delim, що входить до бібліотеки читання , можна вказати додатковий параметр:

locale = locale(decimal_mark = ",")

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

* Точка з комою у другому рядку означає, що read_delim прочитає розділені значеннями csv крапки з комою.

Це допоможе прочитати всі числа із комою як власні числа.

З повагою

Матеуш Канія


3

Ми також можемо використовувати 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)

1

Я думаю, що попередня обробка - це шлях. Ви можете використовувати 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)для читання файлу.


22
Все, що ви можете сценарію, вам слід. Роблячи це вручну, створює можливість помилки, а також не дуже відтворюваного.
Хадлі
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.