Иерархическая агрегация данных и манипулирование - PullRequest
0 голосов
/ 07 января 2019

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

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

Данные выглядят примерно так:

df <- data.frame(
"Reporter" = c("USA", "USA", "USA", "USA", "USA", "USA","USA","EU", "EU","EU", "EU", "EU", "EU", "EU", "EU"),
"Partner" = c( "EU", "EU","EU","EU", "EU","EU","EU","USA", "USA", "USA","USA","USA", "USA","USA", "USA"), 
"Product cat." = c("1", "1.1", "1.2","2", "2.1", "2.2","3","1", "1.1","2", "2.1", "2.2","3","3.1", "3.2"), 
"Year" = c(1970, 1970, 1970, 1970, 1970, 1970,1970, 1970, 1970, 1970, 1970, 1970, 1970, 1970, 1970), 
"Val" = c(200, 170, 30, 100, 50, 40,  220, 230, 180, 80, 50, 20, 170, 40, 130), 
stringsAsFactors = FALSE)

Категории продуктов 1.1 (например, яблоко) и 1.2 (например, бананы) являются категориями субпродуктов категории 1 (например, фрукты). Категории продуктов 2.1 и 2.2 являются подкатегориями продуктов cat. 2 и т. Д.

Мои конечные цели заключаются в следующем: Во-первых, «ценность» категорий субпродукта всегда должна равняться более высокому значению категории продукта. Это случай экспорта США в ЕС, продукт cat 1.1 (val = 170) и 1.2 (val = 30) в совокупности до уровня продукта cat 1 (val = 200). Тем не менее, это часто не так. Например, в случае экспорта США в ЕС значение продукта cat 2.1 (val = 50) и 2.2 (val = 40) меньше, чем продукт cat 2 (val = 100). Чтобы справиться с этой проблемой, мне нужно создать новый субпродукт cat. В идеале это (автоматически) объединяет начало названия продукта cat с K (следовательно, 2.K). Это должно быть дано значение разности между продуктом cat 2 и его подпродуктом cat 2.1 и 2.2 (2.K = 100- (50 + 40) = 10). Кроме того, я хотел бы применить тот же подход к случаям, когда у меня нет данных по одной из категорий субпродуктов. Примером может служить экспорт из ЕС в США, где есть только значения для продукта категории 1 и субпродукта категории 1.1, но нет информации для категории 1.2. В идеале я хотел бы создать новый продукт cat (1.K) со значением разницы между продуктом cat 1 (val = 230) и его подпродуктом cat 1.1 (val = 180). Следовательно, значение 1.k будет 230-180 = 50.

Вторая проблема заключается в том, что в некоторых случаях у меня нет данных по категориям под-продуктов, но у меня есть данные только на агрегированном уровне. Как и в случае экспорта США в ЕС товар категории 3 (который не имеет подкатегорий). Я хотел бы создать новую подкатегорию cat, которая объединяет начало cat продукта с M (следовательно, 2.M) и включает значение на уровне категории продукта, которое не сообщается на уровне подкатегории. Следовательно, например, в случае экспорта США в ЕС продукт категории 3 (220), 3.M = 220.

Как уже упоминалось, я думаю, что есть два шага для решения моих проблем с кодированием. Первый способ состоит в том, как агрегировать данные, которые являются иерархическими (обратите внимание, что в моих фактических данных у меня есть три , а не два, уровень субпродукта (например, 1 еда, 1.1 фрукты, 1.1.1 яблоки). В идеале я бы предпочел избегать создания новых столбцов, так как мой набор данных включает в себя сотни категорий продуктов. Вторая часть посвящена выполнению определенных операций, описанных выше: 1) создание новой категории с разницей между родительским и дочерним узлами, 2) создание фиктивных дочерних узлов. Я был бы очень благодарен любому, кто мог бы помочь мне с этим, поскольку это является ключом к развитию моей статьи.

Я понимаю, что это сложный вопрос, но частичные ответы очень приветствуются.

Заранее благодарю всех за помощь

==============

Спасибо большое LAP за вашу помощь, Вот проблема, с которой я сталкиваюсь с реальными данными после применения функции

split2 <- lapply(split1, function(x){
y <- rbind.data.frame(x, x[1,])
y[nrow(y), "Product.cat."] <- paste0(y[nrow(y), "Prodcat2"], "k")
y[nrow(y), "Val"] <- x[1, "Val"] - sum(x[2:nrow(x), "Val"])
return(y)
})

и функция split3 <- do.call (rbind, split2) </p>

а вот dput из головы двух сплитов

>dput(Headsplit2)
list(`Algeria.United Arab Emirates.05` = structure(list(Reporter = 
c("Algeria", 
"Algeria", "Algeria", "Algeria"), Partner = c("United Arab Emirates", 
"United Arab Emirates", "United Arab Emirates", "United Arab 
Emirates"
), Year = c(2001L, 2001L, 2001L, 2001L), Product.cat. = c("05", 
"052", "054", "05k"), `Commodity Description` = c("Fruit and 
vegetables", 
"Dried fruit including artificially dehydrated", "Vegetables, roots & 
tubers, fresh or dried", 
"Fruit and vegetables"), `Trade Value` = 
structure(c(7.61814641291993e-319, 
7.4539189922423e-319, 1.64178014113046e-320, 7.61814641291993e-319
), class = "integer64"), Prodcat1 = c("0", "0", "0", "0"), Prodcat2 = 
c("05", 
"05", "05", "05")), row.names = c(NA, -4L), vars = c("Reporter", 
"Partner", "Prodcat2", "Year"), drop = TRUE, indices = list(0:2), 
group_sizes = 3L, biggest_group_size = 3L, labels = structure(list(
Reporter = "Algeria", Partner = "United Arab Emirates", Prodcat2 = 
"05", 
Year = 2001L), row.names = c(NA, -1L), class = "data.frame", vars = 
c("Reporter", 
"Partner", "Prodcat2", "Year"), drop = TRUE), class = c("grouped_df", 
"tbl_df", "tbl", "data.frame")), `Algeria.United Kingdom.05` = 
structure(list(
Reporter = c("Algeria", "Algeria", "Algeria", "Algeria"), 
Partner = c("United Kingdom", "United Kingdom", "United Kingdom", 
"United Kingdom"), Year = c(2001L, 2001L, 2001L, 2001L), 
Product.cat. = c("05", "053", "054", "05k"), `Commodity Description` 
= c("Fruit and vegetables", 
"Fruit,preserved and fruit preparations", "Vegetables, roots & 
tubers, fresh or dried", 
"Fruit and vegetables"), `Trade Value` = 
structure(c(6.99399328252869e-320, 
3.16547859290487e-320, 3.82802062397798e-320, 6.99399328252869e-320
), class = "integer64"), Prodcat1 = c("0", "0", "0", "0"), 
Prodcat2 = c("05", "05", "05", "05")), row.names = c(NA, 
-4L), vars = c("Reporter", "Partner", "Prodcat2", "Year"), drop = 
TRUE, indices = list(
0:2), group_sizes = 3L, biggest_group_size = 3L, labels = 
structure(list(
Reporter = "Algeria", Partner = "United Kingdom", Prodcat2 = "05", 
Year = 2001L), row.names = c(NA, -1L), class = "data.frame", vars = 
c("Reporter", 
"Partner", "Prodcat2", "Year"), drop = TRUE), class = c("grouped_df", 
"tbl_df", "tbl", "data.frame")), Hungary.Austria.26 = structure(list(
Reporter = c("Hungary", "Hungary", "Hungary", "Hungary", 
"Hungary", "Hungary", "Hungary", "Hungary", "Hungary"), Partner = 
c("Austria", 
"Austria", "Austria", "Austria", "Austria", "Austria", "Austria", 
"Austria", "Austria"), Year = c(2000L, 2001L, 2000L, 2000L, 
2001L, 2000L, 2000L, 2001L, 2000L), Product.cat. = c("26", 
"26", "263", "265", "265", "266", "267", "267", "26k"), `Commodity 
Description` = c("Textile fibres, not manufactured, and waste", 
"Textile fibres, not manufactured, and waste", "Cotton", 
"Vegetable fibres,except cotton and jute", "Vegetable fibres,except 
cotton and jute", 
"Synthetic and regenerated artificial fibres", "Waste materials from 
textile fabrics, incl.rags", 
"Waste materials from textile fabrics, incl.rags", "Textile fibres, 
not manufactured, and waste"
), `Trade Value` = structure(c(7.3714594359514e-318, 
9.95542276370112e-318, 
4.94065645841247e-320, 2.96439387504748e-320, 6.91691904177745e-320, 
2.32210853545386e-319, 6.33886223614319e-318, 9.60957681161225e-318, 
7.3714594359514e-318), class = "integer64"), Prodcat1 = c("2", 
"2", "2", "2", "2", "2", "2", "2", "2"), Prodcat2 = c("26", 
"26", "26", "26", "26", "26", "26", "26", "26")), row.names = c(NA, 
-9L), vars = c("Reporter", "Partner", "Prodcat2", "Year"), drop = 
TRUE, indices = list(
c(0L, 2L, 3L, 5L, 6L), c(1L, 4L, 7L)), group_sizes = c(5L, 
3L), biggest_group_size = 5L, labels = structure(list(Reporter = 
c("Hungary", 
"Hungary"), Partner = c("Austria", "Austria"), Prodcat2 = c("26", 
"26"), Year = 2000:2001), row.names = c(NA, -2L), class = 
"data.frame", vars = c("Reporter", 
"Partner", "Prodcat2", "Year"), drop = TRUE), class = c("grouped_df", 
"tbl_df", "tbl", "data.frame")), Hungary.Belgium.26 = structure(list(
Reporter = c("Hungary", "Hungary", "Hungary", "Hungary", 
"Hungary", "Hungary", "Hungary", "Hungary", "Hungary"), Partner = 
c("Belgium", 
"Belgium", "Belgium", "Belgium", "Belgium", "Belgium", "Belgium", 
"Belgium", "Belgium"), Year = c(2000L, 2001L, 2000L, 2001L, 
2000L, 2001L, 2000L, 2001L, 2000L), Product.cat. = c("26", 
"26", "265", "265", "266", "266", "267", "267", "26k"), `Commodity 
Description` = c("Textile fibres, not manufactured, and waste", 
"Textile fibres, not manufactured, and waste", "Vegetable 
fibres,except cotton and jute", 
"Vegetable fibres,except cotton and jute", "Synthetic and regenerated 
artificial fibres", 
"Synthetic and regenerated artificial fibres", "Waste materials from 
textile fabrics, incl.rags", 
"Waste materials from textile fabrics, incl.rags", "Textile fibres, 
 not manufactured, and waste"
 ), `Trade Value` = structure(c(3.41893426922143e-318, 
7.98410083679454e-318, 
3.95252516672997e-320, 9.73309322307256e-319, 1.67488253940183e-318, 
1.665001226485e-318, 8.49792910846944e-319, 7.70742407512345e-319, 
3.41893426922143e-318), class = "integer64"), Prodcat1 = c("2", 
"2", "2", "2", "2", "2", "2", "2", "2"), Prodcat2 = c("26", 
"26", "26", "26", "26", "26", "26", "26", "26")), row.names = c(NA, 
-9L), vars = c("Reporter", "Partner", "Prodcat2", "Year"), drop = 
TRUE, indices = list(
c(0L, 2L, 4L, 6L), c(1L, 3L, 5L, 7L)), group_sizes = c(4L, 
4L), biggest_group_size = 4L, labels = structure(list(Reporter = 
c("Hungary", 
"Hungary"), Partner = c("Belgium", "Belgium"), Prodcat2 = c("26", 
"26"), Year = 2000:2001), row.names = c(NA, -2L), class = 
 "data.frame", vars = c("Reporter", 
"Partner", "Prodcat2", "Year"), drop = TRUE), class = c("grouped_df", 
"tbl_df", "tbl", "data.frame")), Hungary.Bulgaria.26 = 
structure(list(
Reporter = c("Hungary", "Hungary", "Hungary", "Hungary", 
"Hungary", "Hungary"), Partner = c("Bulgaria", "Bulgaria", 
"Bulgaria", "Bulgaria", "Bulgaria", "Bulgaria"), Year = c(2000L, 
2001L, 2000L, 2001L, 2000L, 2000L), Product.cat. = c("26", 
"26", "266", "266", "267", "26k"), `Commodity Description` = 
c("Textile fibres, not manufactured, and waste", 
"Textile fibres, not manufactured, and waste", "Synthetic and 
regenerated artificial fibres", 
"Synthetic and regenerated artificial fibres", "Waste materials from 
textile fabrics, incl.rags", 
"Textile fibres, not manufactured, and waste"), `Trade Value` = 
structure(c(1.55136612794151e-318, 
1.53160350210786e-319, 4.94065645841247e-321, 4.94065645841247e-321, 
2.96439387504748e-320, 1.55136612794151e-318), class = "integer64"), 
Prodcat1 = c("2", "2", "2", "2", "2", "2"), Prodcat2 = c("26", 
"26", "26", "26", "26", "26")), row.names = c(NA, -6L), vars = 
c("Reporter", 
"Partner", "Prodcat2", "Year"), drop = TRUE, indices = list(c(0L, 
 2L, 4L), c(1L, 3L)), group_sizes = 3:2, biggest_group_size = 3L, 
labels = structure(list(
Reporter = c("Hungary", "Hungary"), Partner = c("Bulgaria", 
"Bulgaria"), Prodcat2 = c("26", "26"), Year = 2000:2001), row.names = 
c(NA, 
-2L), class = "data.frame", vars = c("Reporter", "Partner", 
"Prodcat2", 
"Year"), drop = TRUE), class = c("grouped_df", "tbl_df", "tbl", 
"data.frame")), Hungary.Canada.26 = structure(list(Reporter = 
 c("Hungary", 
 "Hungary", "Hungary"), Partner = c("Canada", "Canada", "Canada"
 ), Year = c(2001L, 2001L, 2001L), Product.cat. = c("26", "265", 
 "26k"), `Commodity Description` = c("Textile fibres, not 
 manufactured, and waste", 
 "Vegetable fibres,except cotton and jute", "Textile fibres, not 
 manufactured, and waste"
 ), `Trade Value` = structure(c(8.89318162514244e-320, 
 6.4228533959362e-320, 
 8.89318162514244e-320), class = "integer64"), Prodcat1 = c("2", 
 "2", "2"), Prodcat2 = c("26", "26", "26")), row.names = c(NA, 
 -3L), vars = c("Reporter", "Partner", "Prodcat2", "Year"), drop = 
 TRUE, indices = list(
 0:1), group_sizes = 2L, biggest_group_size = 2L, labels = 
structure(list(
Reporter = "Hungary", Partner = "Canada", Prodcat2 = "26", 
Year = 2001L), row.names = c(NA, -1L), class = "data.frame", vars = 
c("Reporter", 
"Partner", "Prodcat2", "Year"), drop = TRUE), class = c("grouped_df", 
"tbl_df", "tbl", "data.frame")))

И раскола 3

dput(Headsplit3)

structure(list(Reporter = c("Algeria", "Algeria", "Algeria", 
"Algeria", "Algeria", "Algeria"), Partner = c("United Arab Emirates", 
"United Arab Emirates", "United Arab Emirates", "United Arab 
Emirates", 
"United Kingdom", "United Kingdom"), Year = c(2001L, 2001L, 2001L, 
2001L, 2001L, 2001L), Product.cat. = c("05", "052", "054", "05k", 
"05", "053"), `Commodity Description` = c("Fruit and vegetables", 
"Dried fruit including artificially dehydrated", "Vegetables, roots & 
tubers, fresh or dried", 
"Fruit and vegetables", "Fruit and vegetables", "Fruit,preserved and 
fruit preparations"
), `Trade Value` = structure(c(7.61814641291993e-319, 
7.4539189922423e-319, 
1.64178014113046e-320, 7.61814641291993e-319, 6.99399328252869e-320, 
3.16547859290487e-320), class = "integer64"), Prodcat1 = c("0", 
"0", "0", "0", "0", "0"), Prodcat2 = c("05", "05", "05", "05", 
"05", "05")), row.names = c(NA, -6L), class = c("grouped_df", 
"tbl_df", "tbl", "data.frame"), vars = c("Reporter", "Partner", 
"Prodcat2", "Year"), drop = TRUE, indices = list(0:3, 4:5), 
group_sizes = c(4L, 
2L), biggest_group_size = 4L, labels = structure(list(Reporter = 
c("Algeria", 
"Algeria"), Partner = c("United Arab Emirates", "United Kingdom"
), Prodcat2 = c("05", "05"), Year = c(2001L, 2001L)), row.names = 
c(NA, 
-2L), class = "data.frame", vars = c("Reporter", "Partner", 
"Prodcat2", 
"Year"), drop = TRUE))

Как вы можете видеть, код может идентифицировать, что экспорт Алжира 052 и 054 в Объединенные Арабские Эмираты не суммирует экспорт 05 - (разница только 1), и он правильно создает переменную 05k Тем не менее, торгуемое значение 05k равно 154193 (= к торгуемому значению целых 05), а не равно 1. Вы знаете, почему это может иметь место?

1 Ответ

0 голосов
/ 07 января 2019

Редактировать: Хорошо, я думаю, что понял!


Данные:

df <- data.frame( "Reporter" = c("USA", "USA", "USA", "USA", "USA", "USA","USA", "USA", "USA","USA"), 
                  "Partner" = c( "EU", "EU","EU","EU", "EU","EU","EU", "EU","EU","EU"), 
                  "Product cat." = c("1", "11","111", "12","2", "21", "211", "212", "22", "3"), 
                  "Val" = c(200, 170, 170, 30, 100, 50, 25, 5, 40, 220), stringsAsFactors = FALSE)

Мы начинаем с создания двух вспомогательных переменных Prodcat1 и Prodcat2:

# create new variable Prodcat1 
df1 <- df %>% group_by(Reporter, Partner) %>% mutate(Prodcat1 = str_extract(Product.cat., "^.{1}")) 

# create new variable Prodcat2 for my 2nd level product category 
df1 <- df1 %>% group_by(Reporter, Partner) %>% mutate(Prodcat2 = str_extract(Product.cat., "^.{2}"))

Теперь мы разбиваем данные на две части, одну для завершения, а другую, которая не требует каких-либо операций на третьем уровне:

# to be completed
df2 <- df1 %>%
  group_by(Reporter, Partner, Prodcat2) %>%
  filter(sum(Val[2:n()]) < Val[1])

# no operation on third level
df3 <- df1 %>%
  group_by(Reporter, Partner, Prodcat2) %>%
  filter(!sum(Val[2:n()]) < Val[1] | n() == 1)

Мы делим df2 на Prodcat2, контролируя Reporter и Partner

split1 <- split(df2, interaction(df2$Reporter, df2$Partner, df2$Prodcat2))
split1 <- split1[sapply(split1, nrow) != 0]

и добавьте новую строку, где это необходимо:

split2 <- lapply(split1, function(x){
  y <- rbind.data.frame(x, x[1,])
  y[nrow(y), "Product.cat."] <- paste0(y[nrow(y), "Prodcat2"], "k")
  y[nrow(y), "Val"] <- x[1, "Val"] - sum(x[2:nrow(x), "Val"])
  return(y)
})

Затем мы впервые объединяем данные и сортируем их по оригинальному Product.cat..

split3 <- do.call(rbind, split2)
newdf <- do.call(rbind, list(split3, df3))

newdf <- newdf %>%
  arrange(Product.cat.)

Данные пока:

# A tibble: 11 x 6
# Groups:   Reporter, Partner, Prodcat2 [5]
   Reporter Partner Product.cat.   Val Prodcat1 Prodcat2
   <chr>    <chr>   <chr>        <dbl> <chr>    <chr>   
 1 USA      EU      1              200 1        NA      
 2 USA      EU      11             170 1        11      
 3 USA      EU      111            170 1        11      
 4 USA      EU      12              30 1        12      
 5 USA      EU      2              100 2        NA      
 6 USA      EU      21              50 2        21      
 7 USA      EU      211             25 2        21      
 8 USA      EU      212              5 2        21      
 9 USA      EU      21k             20 2        21      
10 USA      EU      22              40 2        22      
11 USA      EU      3              220 3        NA  

Теперь мы переходим на второй уровень. Сначала мы создаем три части:

# part to complete
df4 <- newdf %>%
  group_by(Reporter, Partner, Prodcat1) %>%
  filter(nchar(Product.cat.) < 3) %>%
  filter(n() == 1 | sum(Val[2:n()]) < Val[1])

# third level rows, which are not necessary here
df5 <- newdf %>%
  group_by(Reporter, Partner, Prodcat1) %>%
  filter(nchar(Product.cat.) == 3)

# second level part already complete
df6 <- newdf %>%
  group_by(Reporter, Partner, Prodcat1) %>%
  filter(nchar(Product.cat.) < 3) %>%
  filter(sum(Val[2:n()]) == Val[1])

Мы снова разделили данные, теперь на Prodcat1, контролируя для Reporter и Partner:

split3 <- split(df4, interaction(df4$Reporter, df4$Partner, df4$Prodcat1))
split3 <- split3[sapply(split3, nrow) != 0]

Создаем новые строки:

split4 <- lapply(split3, function(x){
  if(nrow(x) == 1){
    y <- rbind.data.frame(x, x)
    y[2, "Product.cat."] <- paste0(y[2, "Prodcat1"], "m")
  }else{
    y <- rbind.data.frame(x, x[1,])
    y[nrow(y), "Product.cat."] <- paste0(y[nrow(y), "Prodcat1"], "k")
    y[nrow(y), "Val"] <- x[1, "Val"] - sum(x[2:nrow(x), "Val"])
  }
  return(y)
})

и мы соединяем все вместе, сортируем снова и отбрасываем вспомогательные переменные.

split5 <- do.call(rbind, split4)
finaldf <- do.call(rbind, list(split5, df5, df6))

finaldf <- finaldf %>%
  ungroup() %>%
  arrange(Product.cat.) %>%
  select(-c("Prodcat1", "Prodcat2"))

Окончательные данные:

# A tibble: 13 x 4
   Reporter Partner Product.cat.   Val
   <chr>    <chr>   <chr>        <dbl>
 1 USA      EU      1              200
 2 USA      EU      11             170
 3 USA      EU      111            170
 4 USA      EU      12              30
 5 USA      EU      2              100
 6 USA      EU      21              50
 7 USA      EU      211             25
 8 USA      EU      212              5
 9 USA      EU      21k             20
10 USA      EU      22              40
11 USA      EU      2k              10
12 USA      EU      3              220
13 USA      EU      3m             220

Наконец, мы очищаем нашу среду от всех временных объектов, которые нам нужны

rm(df1, df2, df3, df4, df5, df6, newdf, split1, split2, split3, split4, split5)

, что оставляет нам исходный набор данных df и окончательный, завершенный набор данных finaldata:)

...