Как заменить пропущенные значения медианой для переменной, используя gsub в R?

#r #regex #gsub

#r #регулярное выражение #gsub

Вопрос:

У меня есть фрейм данных, который я извлек из html-файла таблицы страниц Википедии. Я хочу заменить недостающие значения медианой каждой переменной.

Из приведенных подсказок я знаю, что мне нужно преобразовать factor тип в numeric значения, и мне, вероятно, нужно использовать as.numeric(gsub()) .

 renew$Hydro[grep('\s', renew$Hydro)]
as.numeric(gsub('', median(as.numeric(renew$Hydro)), renew$Hydro))
lapply(renew, function(x) as.numeric(gsub('', median(as.numeric(x)), x)))
  

Я попытался использовать grep() , чтобы показать, что '\s' это шаблон для извлечения пробелов, но пробелы были фактически исключены из вывода, и были показаны только цифры.

Когда я попытался использовать as.numeric(gsub()) , результат выглядел так:

 [1] 5.415405e 13 5.475475e 13 5.475425e 07 5.475415e 13 5.400000e 01 5.400000e 01 5.435405e 16
[8] 5.425435e 13 5.400000e 01 5.415455e 16 5.445425e 16 5.415495e 13 5.400000e 01 5.400000e 01
  

что совсем не похоже на фрейм данных, который выглядит как:

 [1] 1035.3   7782     72       7109                       30134.8  2351.2            15318   
  

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

Редактировать: так выглядит начало фрейма данных. Это из «https://en.wikipedia.org/wiki/List_of_countries_by_electricity_production_from_renewable_sources «.

 > renew
                             Country    Hydro     Wind     Bio   Solar
1                        Afghanistan   1035.3      0.1            35.5
2                            Albania     7782                      1.9
3                            Algeria       72     19.4           339.1
4                             Angola     7109              155    18.3
5                           Anguilla                               2.4
6                Antigua and Barbuda                               5.5
7                          Argentina  30134.8    554.1  1820.4    14.5
8                            Armenia   2351.2      1.8             1.2
9                              Aruba             130.3     8.9     9.2
10                         Australia    15318    12199    3722    6209
11                           Austria    42919     5235    4603    1096
12                        Azerbaijan   1959.3     22.8   174.5    35.3
13                           Bahamas                               1.9
14                           Bahrain               1.2             8.3
15                        Bangladesh      946      5.1     7.7   224.3
  

Комментарии:

1. Я был бы рад помочь с этим, если бы вы могли предоставить некоторые примеры данных.

2. добавлен заголовок фрейма данных, надеюсь, это поможет

3. Возможно, стоит вернуться на несколько шагов назад и попытаться в первую очередь правильно настроить ваши данные. Country должно быть символом / фактором, но все остальные столбцы, которые вы показываете, должны быть числовыми, поэтому вы должны посмотреть, сможете ли вы а) прочитать их как числовые или б) преобразовать их в числовые сразу после их чтения. gsub() обычно используется для изменения текстовых данных, поэтому вам, вероятно, будет сложно применить его к числовым данным.

Ответ №1:

Поскольку у вас есть пустые пробелы в вашем фрейме данных, столбцы превращаются в символы, и нет смысла брать median столбцы символов. Мы можем сначала заменить пустые пробелы на NA , преобразовать столбцы в числовые, а затем replace NA s на median столбец. Используя dplyr , мы могли бы выполнить следующие шаги.

 library(dplyr)
renew[renew == ""] <- NA

renew %>%
   mutate_at(-1, as.numeric) %>% #-1 is to ignore Country column
   mutate_at(-1, ~ replace(., is.na(.), median(., na.rm = TRUE)))


#             Country   Hydro    Wind    Bio  Solar
#1        Afghanistan  1035.3     0.1  174.5   35.5
#2            Albania  7782.0    21.1  174.5    1.9
#3            Algeria    72.0    19.4  174.5  339.1
#4             Angola  7109.0    21.1  155.0   18.3
#5           Anguilla  4730.1    21.1  174.5    2.4
#6  AntiguaandBarbuda  4730.1    21.1  174.5    5.5
#7          Argentina 30134.8   554.1 1820.4   14.5
#8            Armenia  2351.2     1.8  174.5    1.2
#9              Aruba  4730.1   130.3    8.9    9.2
#10         Australia 15318.0 12199.0 3722.0 6209.0
#11           Austria 42919.0  5235.0 4603.0 1096.0
#12        Azerbaijan  1959.3    22.8  174.5   35.3
#13           Bahamas  4730.1    21.1  174.5    1.9
#14           Bahrain  4730.1     1.2  174.5    8.3
#15        Bangladesh   946.0     5.1    7.7  224.3
  

Мы могли бы сделать то же самое, используя базовый R

 renew[renew == ""] <- NA
renew[-1] <- lapply(renew[-1], function(x) 
      as.numeric(replace(x, is.na(x), median(as.numeric(x), na.rm = TRUE))))
  

Комментарии:

1. Кажется, это работает хорошо, но когда я запускаю базовый код R, все значения фрейма данных меняются. Я получаю [1] 6.0 143.0 141.0 140.0 81.5 81.5 81.0 вместо [1] 1035.3 7782 72 7109

2. @LaurelDaly, похоже, работает для меня. Вы применили базовый код R к измененному renew фрейму данных?

Ответ №2:

Я хотел бы отметить, что данные еще не очищены сразу после очистки, поскольку lapply(renew, function(x) grep(",", x)) что-то дает.

Сначала очистите его с gsub помощью, чтобы избежать преобразования этих значений в NA s при преобразовании данных в числовые. Здесь одноэтапное решение, правильные NA значения создаются автоматически:

 renew[-1] <- lapply(renew[-1], function(x) as.numeric(as.character(gsub(",", ".", x))))
  

После этого вы можете запустить sapply

 # sapply(2:5, function(x) renew[[x]][is.na(renew[[x]])] <<- median(renew[[x]], na.rm=TRUE))
  

или, конечно, более короткая адаптация второй базовой строки R-кода @Ronak Shah, что намного лучше:

 renew[-1] <- sapply(renew[-1], function(x) replace(x, is.na(x), median(x, na.rm=TRUE)))
  

Результат

 summary(renew)
#                      country        hydro                wind                bio              solar        
# Afghanistan        :  1   Min.   :      0.8   Min.   :     0.00   Min.   :    0.2   Min.   :    0.1  
# Albania            :  1   1st Qu.:    907.8   1st Qu.:    50.45   1st Qu.:  151.1   1st Qu.:    4.8  
# Algeria            :  1   Median :   2595.0   Median :   109.00   Median :  242.5   Median :   22.3  
# Angola             :  1   Mean   :  19989.3   Mean   :  4324.13   Mean   : 2136.3   Mean   : 1483.3  
# Anguilla           :  1   3rd Qu.:   7992.4   3rd Qu.:   293.55   3rd Qu.:  344.4   3rd Qu.:  124.5  
# Antigua and Barbuda:  1   Max.   :1193370.0   Max.   :242387.70   Max.   :69017.0   Max.   :67874.1  
# (Other)            :209                                                                              
  

Данные

 library(rvest)
renew <- setNames(html_table(
  read_html(paste0("https://en.wikipedia.org/wiki/List_of_countries",
                   "_by_electricity_production_from_renewable_sources")),
  fill=TRUE, header=TRUE)[[1]][c(1, 6:9)], c("country", "hydro", "wind", "bio", "solar"))
renew$country <- factor(renew$country)
  

Ответ №3:

Мы могли бы сделать это компактно с na.aggregate помощью from zoo

 library(dplyr)
library(hablar)
library(zoo)
renew %>%
    retype %>% # change the type of columns
    # replace missing value of numeric columns with median
     mutate_if(is.numeric, na.aggregate, FUN = median)
# A tibble: 15 x 5
#   Country              Hydro    Wind    Bio  Solar
#   <chr>                <dbl>   <dbl>  <dbl>  <dbl>
# 1 Afghanistan          1035.     0.1  174.    35.5
# 2 Albania              7782     21.1  174.     1.9
# 3 Algeria                72     19.4  174.   339. 
# 4 Angola               7109     21.1  155     18.3
# 5 Anguilla             4730.    21.1  174.     2.4
# 6 Antigua and Barbuda  4730.    21.1  174.     5.5
# 7 Argentina           30135.   554.  1820.    14.5
# 8 Armenia              2351.     1.8  174.     1.2
# 9 Aruba                4730.   130.     8.9    9.2
#10 Australia           15318  12199   3722   6209  
#11 Austria             42919   5235   4603   1096  
#12 Azerbaijan           1959.    22.8  174.    35.3
#13 Bahamas              4730.    21.1  174.     1.9
#14 Bahrain              4730.     1.2  174.     8.3
#15 Bangladesh            946      5.1    7.7  224. 
  

данные

 renew <- structure(list(Country = c("Afghanistan", "Albania", "Algeria", 
"Angola", "Anguilla", "Antigua and Barbuda", "Argentina", "Armenia", 
"Aruba", "Australia", "Austria", "Azerbaijan", "Bahamas", "Bahrain", 
"Bangladesh"), Hydro = c("1035.3", "7782", "72", "7109", "", 
"", "30134.8", "2351.2", "", "15318", "42919", "1959.3", "", 
"", "946"), Wind = c("0.1", "", "19.4", "", "", "", "554.1", 
"1.8", "130.3", "12199", "5235", "22.8", "", "1.2", "5.1"), Bio = c("", 
"", "", "155", "", "", "1820.4", "", "8.9", "3722", "4603", "174.5", 
"", "", "7.7"), Solar = c(35.5, 1.9, 339.1, 18.3, 2.4, 5.5, 14.5, 
1.2, 9.2, 6209, 1096, 35.3, 1.9, 8.3, 224.3)), row.names = c("1", 
"2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", 
"14", "15"), class = "data.frame")