Как я уже упоминал в нескольких постах в блоге, я изучал набор платных данных Земельной книги и, хотя я изначально использовал SparkR, мне было любопытно, насколько просто будет исследовать набор данных с использованием простого R.
Я подумал, что начну с загрузки данных в фрейм данных и запускаю те же запросы с помощью deployer.
Я уже сталкивался с библиотекой readr Хэдли Уикхема, но не использовал ее, и, поскольку мне нужно было загрузить CSV-файл объемом 20 миллионов строк, это казалось идеальным временем, чтобы попробовать.
Цель readr — обеспечить быстрый и удобный способ чтения табличных данных в R.
Давайте начнем:
|
1
2
3
4
5
6
7
|
> library(readr) > system.time(read_csv("pp-complete.csv", col_names = FALSE)) user system elapsed 127.367 21.957 159.963 > df = read_csv("pp-complete.csv", col_names = FALSE) |
Таким образом, процесс обработки файла CSV в кадр данных занял чуть более 2 минут. Давайте кратко рассмотрим его содержимое:
|
01
02
03
04
05
06
07
08
09
10
11
12
|
> head(df)Source: local data frame [6 x 16] X1 X2 X3 X4 X5 X6 X7 X8 X9 (chr) (int) (date) (chr) (chr) (chr) (chr) (chr) (chr)1 {0C7ADEF5-878D-4066-B785-0000003ED74A} 163000 <NA> UB5 4PJ T N F 106 2 {35F67271-ABD4-40DA-AB09-00000085B9D3} 247500 <NA> TA19 9DD D N F 58 3 {B20B1C74-E8E1-4137-AB3E-0000011DF342} 320000 <NA> W4 1DZ F N L 58 4 {7D6B0915-C56B-4275-AF9B-00000156BCE7} 104000 <NA> NE61 2BH D N F 17 5 {47B60101-B64C-413D-8F60-000002F1692D} 147995 <NA> PE33 0RU D N F 4 6 {51F797CA-7BEB-4958-821F-000003E464AE} 110000 <NA> NR35 2SF T N F 5 Variables not shown: X10 (chr), X11 (chr), X12 (chr), X13 (chr), X14 (chr), X15 (chr), address (chr) |
Теперь давайте запросим фрейм данных, чтобы узнать, какой почтовый индекс имеет самую высокую среднюю цену продажи. Нам нужно сгруппировать по столбцу ‘X4’ перед применением некоторых агрегатных функций:
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
> library(dplyr) > system.time(df %>% group_by(X4) %>% summarise(total = sum(as.numeric(X2)), count = n(), ave = total / count) %>% arrange(desc(ave))) user system elapsed 122.557 1.135 124.211 Source: local data frame [1,164,396 x 4] X4 total count ave (chr) (dbl) (int) (dbl)1 SW7 1DW 39000000 1 390000002 SW1W 0NH 32477000 1 324770003 W1K 7PX 27000000 1 270000004 SW1Y 6HD 24750000 1 247500005 SW6 1BA 18000000 1 180000006 SW1X 7EE 101505645 6 169176087 N6 4LA 16850000 1 168500008 EC4N 5AE 16500000 1 165000009 W8 7EA 82075000 6 1367916710 W1K 1DP 13500000 1 13500000 |
А что если вместо средней цены по почтовому индексу мы хотим найти самую дорогую недвижимость из когда-либо проданных?
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
|
> system.time(df %>% group_by(X4) %>% summarise(max = max(X2)) %>% arrange(desc(max))) user system elapsed 35.438 0.478 36.026 Source: local data frame [1,164,396 x 2] X4 max (chr) (int)1 SW10 9SU 549590002 SW7 1QJ 500000003 SW1X 8HG 460133654 SW7 1DW 390000005 SW1W 0NH 324770006 SW1X 7LJ 293500007 W8 7EA 279000008 SW3 3SR 277500009 W1K 7PX 2700000010 SW1X 7EE 25533000.. ... ... |
Интересно, что этот был намного быстрее, чем первый, хотя кажется, что мы проделали чуть меньше работы.
В этот момент я упомянул о своем эксперименте Ашоку, который предложил мне дать data.table попытку проверить, получилось ли это лучше. Я не использовал его раньше, но смог довольно быстро его запустить и запустить :
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
> library(data.table) > system.time(fread("pp-complete.csv", header = FALSE))Read 20075122 rows and 15 (of 15) columns from 3.221 GB file in 00:01:05 user system elapsed 59.324 5.798 68.956 > dt = fread("pp-complete.csv", header = FALSE) > head(dt) V1 V2 V3 V4 V5 V6 V7 V8 V91: {0C7ADEF5-878D-4066-B785-0000003ED74A} 163000 2003-02-21 00:00 UB5 4PJ T N F 106 2: {35F67271-ABD4-40DA-AB09-00000085B9D3} 247500 2005-07-15 00:00 TA19 9DD D N F 58 3: {B20B1C74-E8E1-4137-AB3E-0000011DF342} 320000 2010-09-10 00:00 W4 1DZ F N L 58 4: {7D6B0915-C56B-4275-AF9B-00000156BCE7} 104000 1997-08-27 00:00 NE61 2BH D N F 17 5: {47B60101-B64C-413D-8F60-000002F1692D} 147995 2003-05-02 00:00 PE33 0RU D N F 4 6: {51F797CA-7BEB-4958-821F-000003E464AE} 110000 2013-03-22 00:00 NR35 2SF T N F 5 V10 V11 V12 V13 V14 V151: READING ROAD NORTHOLT NORTHOLT EALING GREATER LONDON A2: ADAMS MEADOW ILMINSTER ILMINSTER SOUTH SOMERSET SOMERSET A3: WHELLOCK ROAD LONDON EALING GREATER LONDON A4: WESTGATE MORPETH MORPETH CASTLE MORPETH NORTHUMBERLAND A5: MASON GARDENS WEST WINCH KING'S LYNN KING'S LYNN AND WEST NORFOLK NORFOLK A6: WILD FLOWER WAY DITCHINGHAM BUNGAY SOUTH NORFOLK NORFOLK A |
Таким образом, мы уже выиграли одну минуту за время разбора, что довольно приятно. Давайте попробуем найти почтовый индекс с самой высокой средней ценой:
|
1
2
|
> dt[,list(length(V2), sum(V2)), by=V4][, V2 / V1, by=V4][order(-V1)][1:10]Error in sum(V2) : invalid 'type' (character) of argument |
Хммм, похоже, нам нужно сделать столбец ‘V2’ числовым. Давайте сделаем это:
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
|
> dt = dt[, V2:= as.numeric(V2)] > dt[,list(length(V2), sum(V2)), by=V4][, V2 / V1, by=V4][order(-V1)][1:10] user system elapsed 5.108 0.670 6.183 V4 V1 1: SW7 1DW 39000000 2: SW1W 0NH 32477000 3: W1K 7PX 27000000 4: SW1Y 6HD 24750000 5: SW6 1BA 18000000 6: SW1X 7EE 16917608 7: N6 4LA 16850000 8: EC4N 5AE 16500000 9: W8 7EA 1367916710: W1K 1DP 13500000 |
Это немного быстрее, чем наша версия фрейма данных — ~ 5 секунд по сравнению с ~ 2 минутами. Мы потеряли столбцы общего объема продаж и количества продаж, но я ожидаю, что это только потому, что мой data.table foo слаб, и мы могли бы сохранить их, если захотим.
Но хорошее начало с точки зрения времени исполнения. Теперь давайте попробуем максимальную цену продажи по запросу по почтовому индексу:
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
|
> system.time(dt[,list(max(V2)), by=V4][order(-V1)][1:10]) user system elapsed 3.684 0.358 4.132 V4 V1 1: SW10 9SU 54959000 2: SW7 1QJ 50000000 3: SW1X 8HG 46013365 4: SW7 1DW 39000000 5: SW1W 0NH 32477000 6: SW1X 7LJ 29350000 7: W8 7EA 27900000 8: SW3 3SR 27750000 9: W1K 7PX 2700000010: SW1X 7EE 25533000 |
Мы получили те же результаты, что и раньше, и на этот раз это заняло ~ 4 секунды по сравнению с ~ 35 секундами.
На самом деле мы можем сделать еще лучше, если мы установим столбец почтового индекса в качестве ключа:
|
1
2
3
4
5
6
7
8
9
|
> setkey(dt, V4) > system.time(dt[,list(length(V2), sum(V2)), by=V4][, V2 / V1, by=V4][order(-V1)][1:10]) user system elapsed 1.500 0.047 1.548 > system.time(dt[,list(max(V2)), by=V4][order(-V1)][1:10]) user system elapsed 0.578 0.026 0.604 |
И это все, что я имею в своем эксперименте. Если есть что-то еще, что я могу сделать, чтобы ускорить любую из версий, дайте мне знать в комментариях.
Да, и для небольшого количества комментариев о том, что мы можем узнать из запросов … Найтсбридж — это очень дорогая область для жизни!
| Ссылка: | Р: Запрос файла CSV из 20 миллионов строк — data.table против фрейма данных от нашего партнера по JCG Марка Нидхэма в блоге Марка Нидхэма . |