Фильтровать (иерархические) данные по условиям и подкатегориям - PullRequest
0 голосов
/ 07 января 2019

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

мои данные об экспорте выглядят примерно так, но для разных стран и лет.

df3dgt <- data.frame(
"Reporter" = c("USA", "USA", "USA", "USA", "USA", "USA","USA", "USA", "USA","USA","EU", "EU","EU","EU","EU", "EU","EU","EU","EU"),
"Partner" = c( "EU", "EU","EU","EU", "EU","EU","EU", "EU","EU","EU","USA", "USA", "USA","USA","USA", "USA", "USA","USA","USA"), 
"Commodity code" = c("1", "11", "111", "112", "12","2", "21","211", "22", "3", "1", "11", "111", "112", "2", "21", "211", "212", "22"), 
 "Value" = c( 100, 50, 25, 5, 40, 200, 170, 170, 30, 220, 190, 190, 120, 30, 300, 200, 150, 50, 100), 
 stringsAsFactors = FALSE)

Товарные коды агрегируют данные на разных уровнях. Например, 111 (например, яблоко) и 112 (например, бананы) являются подгруппами товара 11 (например, фрукты), аналогично, 11 (фрукты) и 12 (овощи) являются подкатегориями 1 (например, еда).

Мне нужно отфильтровать данные, чтобы отделить полные данные от остальных.

Я хочу фильтровать в соответствии с двумя условиями:

(1) фильтровать данные, где «значение» категорий суб-товаров равно значению, сообщаемому на более высоком уровне агрегации. Например, товарный код 1 экспорта США в ЕС является неполным. Товар 112 (val = 5) и товар 111 (val = 25) не суммируются со стоимостью товара 11 (val = 50). аналогично значения 11 (val = 50) и 12 (val = 40) не агрегируются в значение товарного кода 1 (100) И наоборот, категория 2 экспорта ЕС в США завершена. Товар 211 (val = 150) и 212 (val = 50) агрегируют до уровня товара 21 (val = 200). Также значения товарных категорий 21 (200) и 22 (100) агрегируются до уровня товара 2.

2) Мне также нужно отфильтровывать отдельно данные, которые сообщаются только на более высоких уровнях товарного кода. Для справки о том, какие данные сообщаются только на более высоких уровнях, рассмотрите иллюстративный перечень товарного кода ниже:

 Comlist <- c("1", "11", "111", "112", "12","2", "21","211", "22","221", "3","31", "32", "311", "321")
 Comlist <- as.data.frame(Comlist)

Следовательно, я хочу отфильтровать в экспорте между США и ЕС товар 22, потому что я знаю, что категория 221 существует, и о ней не сообщается. Аналогичным образом, для категории 3 она не сообщается на более низких уровнях.

Чтобы справиться с (1), я рассматриваю один уровень за один раз (сначала двух- и трехзначная категория продукта, а затем один и два). Сначала я создаю новую переменную для каждого уровня категории продукта

# 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
df2 <- df1 %>%
group_by(Reporter, Partner) %>%
mutate(Prodcat2 = str_extract(Product.cat., "^.{2}"))  

Тогда я фильтрую

 df2.Incomplete <- df2 %>%
 group_by(Reporter, Partner, Prodcat2) %>%
 filter(sum(Val[2:n()]) < Val[1])`

Это, однако, включает только данные с товарным кодом из двух или трех цифр, в то время как я хотел бы также включить 1-ю цифру неполных данных. например он сообщает строки с «товарным кодом» 111 и 11, но не с товарным кодом «1» неполных групп. Более того, я не уверен, что приступлю к фильтрации для случая (2), учитывая, что мне нужно рассмотреть сто стран и категорий продуктов.

Заранее большое спасибо за помощь.

1 Ответ

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

Все еще немного сбивает с толку, какова ваша цель. Но вот функция, которая может помочь:

Функция

# check function
checkLowerLevels <- function (df = df3dgt, defaultValue = TRUE) {
  # set column commodity.code to integer
  class(df$Commodity.code) <- 'integer' 
  # checks
  out <- vapply(1:nrow(df), function (k, defaultValue) {
    # Checks at lower level if values add up to parent level
    # if no lower exists, default value is TRUE.
    # 
    # For a given incomplete parent return parent + children
    # separated by ';' (can be split using strsplit).
    currentCode <- .subset2(df, 3)[k]
    currentRepo <- .subset2(df, 1)[k]
    currentPart <- .subset2(df, 2)[k]
    lowerLevels <- (.subset2(df, 3) > currentCode*10-1) & (.subset2(df, 3) < (currentCode+1)*10) & (.subset2(df, 1) == currentRepo) & (.subset2(df, 2) == currentPart)
    check <- ifelse(!any(lowerLevels), defaultValue, sum(.subset2(df, 4L)[lowerLevels]) == .subset2(df, 4L)[k])
    res <- NA_character_
    if (check) return (c(res,check))
    res <- paste(currentCode, paste(.subset2(df, 3L)[lowerLevels], collapse = ';'), sep = ';')
    return(c(res,check)) 
  }, character(2), defaultValue = defaultValue)
  out <- t(out)
  ans <- data.frame(check=out[,2], subset=out[,1], stringsAsFactors = FALSE)
  class(ans$check) <- 'logical'
  ans
}

Результат

Вот приложение:

# create new columns in data frame
df3dgt <- cbind(df3dgt, checkLowerLevels())
df3dgt 
#    Reporter Partner Commodity.code Value check     subset
# 1       USA      EU              1   100 FALSE    1;11;12
# 2       USA      EU             11    50 FALSE 11;111;112
# 3       USA      EU            111    25  TRUE       <NA>
# 4       USA      EU            112     5  TRUE       <NA>
# 5       USA      EU             12    40  TRUE       <NA>
# 6       USA      EU              2   200  TRUE       <NA>
# 7       USA      EU             21   170  TRUE       <NA>
# 8       USA      EU            211   170  TRUE       <NA>
# 9       USA      EU             22    30  TRUE       <NA>
# 10      USA      EU              3   220  TRUE       <NA>
# 11       EU     USA              1   190  TRUE       <NA>
# 12       EU     USA             11   190 FALSE 11;111;112
# 13       EU     USA            111   120  TRUE       <NA>
# 14       EU     USA            112    30  TRUE       <NA>
# 15       EU     USA              2   300  TRUE       <NA>
# 16       EU     USA             21   200  TRUE       <NA>
# 17       EU     USA            211   150  TRUE       <NA>
# 18       EU     USA            212    50  TRUE       <NA>
# 19       EU     USA             22   100  TRUE       <NA>

Объяснение

  • Функция checkLowerLevels проверяет полноту для любого кода n, отфильтрованного репортером и партнером (таким образом, n = 1 обрабатывается один раз для USA -> EU и один раз для 'EU -> USA')
  • Для этого он автоматически выглядит на один уровень ниже и сравнивает агрегированное значение ниже с верхними значениями
  • Если код неполный, он также возвращает код n и подуровни n1, n2, ..., nm в формате n;n1;n2;...;nm
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...