Суммирование строк с определенным значением в сгруппированных данных в R

У меня есть набор данных "область"

House_No. Info_On_Area
1a        Names of neighbouringhouse in 100m  1b   1c    1d    1e 
1a        Area of neighbouringhouse  in 100m  500  1000  1500  300
1a        Names of neighbouringhouse in 300m  1b   1c    1d    1e   1f    1g   1h
1a        Area of neighbouringhouse  in 300m  500  1000  1500  300  600   400  2000
2a        Names of neighbouringhouse in 100m  2b   2c    2d    2e 
2a        Area of neighbouringhouse  in 100m  500  1000  1500  300
2a        Names of neighbouringhouse in 300m  2b   2c    2d    2e   2f    2g   2h
2a        Area of neighbouringhouse  in 300m  500  1000  1500  300  600   400  2000

Я хочу создать фрейм данных, в котором таблица будет отображаться как

House_No. Area of neighbouringhouse in 100m Area of neighbouringhouse  in 300m 

Я использовал dplyr и сгруппировал разные номера домов CT ‹- data.frame (но%>% group_by (House_No.)) и попытался использовать rowSums. Однако я получил ошибку о том, что информация не является числовой. Я думаю, это потому, что мне нужно преобразовать числа в значениях строк как числа, и я не уверен, как это сделать. Я застрял на этом этапе и не мог двигаться дальше.

Я изучал похожие решения, но, похоже, у них нет фрейма данных, в котором они работают над суммированием значений строк, таких как Сумма строк в data.frame или матрице, Сумма по строкам в R.

Буду признателен за любую помощь! Спасибо :)


person Keerthi Krutha    schedule 15.12.2019    source источник
comment
предоставьте образец ваших данных с помощью dput(head(df, 10))   -  person AlexB    schedule 15.12.2019


Ответы (2)


Используйте stringr::str_extract_*, чтобы получить цифры, затем выполните spread, используя pivot_wider

library(tidyverse)
df %>%  
   #extract everything up to 1+ digits followed by m
   mutate(flag = str_extract(Info_On_Area,'.*\\d+m'), 
          #extract any 1 or more digits followed by space or at the end
          SumArea = map_dbl(Info_On_Area, ~sum(as.numeric(str_extract_all(.x, '\\d+(?=\\s|$)', simplify = TRUE))))) %>% 
   filter(str_detect(Info_On_Area, 'Area')) %>% 
   #As suggested by @Uwe
   pivot_wider(id_cols = House_No., names_from = flag, values_from = SumArea)

# A tibble: 2 x 3
  House_No. `Area of neighbouringhouse  in 100m` `Area of neighbouringhouse  in 300m`
  <chr>                                    <dbl>                                <dbl>
1 1a                                        3300                                 6300
2 2a                                        3300                                 6300

Данные

df <- structure(list(House_No. = c("1a", "1a", "1a", "1a", "2a", "2a", 
"2a", "2a"), Info_On_Area = c("Names of neighbouringhouse in 100m  1b   1c    1d    1e", 
"Area of neighbouringhouse  in 100m  500  1000  1500  300", "Names of neighbouringhouse in 300m  1b   1c    1d    1e   1f    1g   1h", 
"Area of neighbouringhouse  in 300m  500  1000  1500  300  600   400  2000", 
"Names of neighbouringhouse in 100m  2b   2c    2d    2e", "Area of neighbouringhouse  in 100m  500  1000  1500  300", 
"Names of neighbouringhouse in 300m  2b   2c    2d    2e   2f    2g   2h", 
"Area of neighbouringhouse  in 300m  500  1000  1500  300  600   400  2000"
)), class = "data.frame", row.names = c(NA, -8L))
person A. Suliman    schedule 15.12.2019
comment
Большое вам спасибо и извините за задержку с ответом. Я могу получить фрейм данных с областью в виде отдельного столбца, однако я получаю свой ответ как «0». Что я здесь делаю не так? - person Keerthi Krutha; 17.12.2019
comment
Пожалуйста. Хм Без данных сложно сказать, но работает ли он в df, также есть Площадь в виде Площадь соседнего дома в 300м 500 1000 1500 300 600 400 2000. Наконец, у вас есть последняя версия tidyverse - person A. Suliman; 17.12.2019

Сложность здесь в том, что информация представлена ​​как в широком, так и в длинном формате. Info_On_Area - это символьный столбец, который содержит имя переменной, а также произвольное количество значений, разделенных пробелом. Следовательно, Info_On_Area необходимо разделить на два этапа. Во-первых, для извлечения имени переменной, а во-вторых, для извлечения чисел для последующего преобразования в числовые и суммирования.

К счастью, OP интересуется только информацией о местности, что упрощает дело.

1. tidyverse подход

library(dplyr)
library(purrr)
library(stringr)
library(tidyr)
area %>% 
  filter(Info_On_Area %>% str_detect("^Area")) %>% 
  separate(Info_On_Area, c("var", "val"), sep = "(?<=00m)") %>% 
  mutate(Area = map_int(val, ~ str_extract_all(. , "\\d+") %>% unlist() %>% as.integer() %>% sum())) %>%
  pivot_wider(id_cols = House_No., names_from = var, values_from = Area)
# A tibble: 2 x 3
  House_No. `Area of neighbouringhouse  in 100m` `Area of neighbouringhouse  in 300m`
  <chr>                                    <int>                                <int>
1 1a                                        3300                                 6300
2 2a                                        3300                                 6300

Результат имеет по одной строке для каждого House_No.. Это отличается от A. Решение Сулимана, которое показывает две строки для каждого House_No. (больше не в отредактированной версии Ответ А. Сулимана < / а>). Другие отличия включают использование функций separate() и pivot_wider(), регулярного выражения с ретроспективой "(?<=00m)" и применение filter() в качестве первого шага в конвейере.

2. Подход data.table

Для полноты картины вот также data.table решение:

library(data.table)
library(magrittr)
setDT(area)[Info_On_Area %like% "^Area", 
            c(.(House_No.= House_No.), tstrsplit(Info_On_Area, "(?<=00m)", perl = TRUE))][
              , str_extract_all(V3, "\\d+") %>% unlist() %>% as.integer() %>% sum(), by = .(House_No., V2)][
                , dcast(.SD, House_No. ~ V2, value.var = "V1")]
   House_No. Area of neighbouringhouse  in 100m Area of neighbouringhouse  in 300m
1:        1a                               3300                               6300
2:        2a                               3300                               6300

Данные

area <- structure(list(House_No. = c("1a", "1a", "1a", "1a", "2a", "2a", 
"2a", "2a"), Info_On_Area = c("Names of neighbouringhouse in 100m  1b   1c    1d    1e", 
"Area of neighbouringhouse  in 100m  500  1000  1500  300", "Names of neighbouringhouse in 300m  1b   1c    1d    1e   1f    1g   1h", 
"Area of neighbouringhouse  in 300m  500  1000  1500  300  600   400  2000", 
"Names of neighbouringhouse in 100m  2b   2c    2d    2e", "Area of neighbouringhouse  in 100m  500  1000  1500  300", 
"Names of neighbouringhouse in 300m  2b   2c    2d    2e   2f    2g   2h", 
"Area of neighbouringhouse  in 300m  500  1000  1500  300  600   400  2000"
)), class = "data.frame", row.names = c(NA, -8L))
person Uwe    schedule 15.12.2019