处理嵌套数据

时间:2019-02-12 20:16:40

标签: r nested data-manipulation

我是r的新手,在处理数据以进行分析时遇到了一些麻烦。如果有人可以帮助,我将不胜感激。

我的数据看起来像这样:

df<- data.frame("Reporter" = c("USA", "USA", "USA", "USA", "USA","USA"),
"Partner" = c( "EU", "EU","EU","EU", "EU","EU"), 
"Product cat." = c("1", "11", "111", "122", "12", "2"), 
"Year" = c(1970, 1970, 1970, 1970, 1970, 1970), 
"trade value" = c( 100, 50, 25, 5, 40, 220), stringsAsFactors = FALSE)

我有多个国家/地区年度观察数据,其中包含有关贸易的贸易数据。向量乘积。 cat 表示要出口哪种商品。 产品的位数越多。 cat ,则贸易信息的分类就越多。例如产品猫。 111(例如苹果)和112(例如香蕉)是产品类别11(例如水果)的子产品类别。产品类别11是食品的子类别(产品类别1)。

要进行分析,我需要以尽可能细分的水平报告所有值-即,我需要所有数据都具有尽可能多的位数。

我的问题是,对于某些国家(地区)年的观察,我只报告了较高汇总水平的数据。例如,考虑以下产品目录cat。作为示例中的比较。

ls.prod.cat<- data.frame(
  "Product cat." = c("1", "11", "111", "122", "12","121","122","2","21","22","211"), 
 stringsAsFactors = FALSE)

在该示例中,我以2位数级别(12)报告了数据,该数据可以以3位数级别(121,122)报告。 我想做的是找到一种方法来对仅在较高聚合级别(例如12)报告的所有数据进行个性化处理,并更改其产品类别。在末尾添加“ m”。 因此,在操纵产品猫之后。 12应该变成 12m

类似地,用于更高级别的聚集。 例如,当仅在产品目录的第一位报告数据时。我想要一个在产品目录末尾添加两个“ mm”的数据。以反映仅在聚合的第一级报告数据。例如,在我的df中,这意味着该数据具有乘积cat。 2应成为产品猫。 2mm

----更新---

总而言之,我正在寻找一种方法来自动区分以较高聚合级别排他报告数据的行,并且这些行会改变产品类别。名称加上相应的m号。仅对于仅具有较高聚合级别数据的数据,应包含“ m”。例如,在该示例中,我不希望有1mm,因为我的数据聚合级别较低(11,12)。同样,我也不想有11m,因为我的数据聚合级别较低(111,112)。我想拥有12m。因为应该存在121和122上的数据(cfr ls.prod.cat),但是仅在更高的聚合级别上报告了该数据(12)。

我知道这是一个非常具体的问题,但是如果有人可以提供帮助,我将不胜感激。

----更新2 ---

考虑更复杂的数据集

df3 <- <- data.frame(
"Reporter" = c("USA", "USA", "USA", "USA", "USA", "USA","USA", "USA", 
"USA","USA","EU", "EU","EU","EU","EU", "EU","EU","EU","EU", "EU", 
"USA", "USA", "USA", "USA", "USA", "USA","USA", "USA", "USA","USA"),
"Partner" = c( "EU", "EU","EU","EU", "EU","EU","EU", 
"EU","EU","EU","USA", "USA", "USA","USA","USA", "USA", 
"USA","USA","USA", "USA", "EU", "EU","EU","EU", "EU","EU","EU", 
"EU","EU","EU"), 
"Product cat." = c("1", "11", "111", "112", "12","2", "21","211", "22", 
"3", "1", "11", "111", "112", "2", "21", "211", "212", "22", "221", 
"1", "11", "111", "112", "12","2", "21","211", "22", "3"), 
"Year" = c(1970, 1970, 1970, 1970, 1970,1970, 1970, 1970, 1970, 1970, 
1970, 1970, 1970, 1970, 1970, 1970, 1970, 1970, 1970, 1970, 1980, 1980, 
1980, 1980,  1980, 1980, 1980, 1980, 1980, 1980), 
"Val" = c( 100, 50, 25, 5, 40, 200, 170, 170, 30, 220, 190, 190, 120, 
30, 300, 200, 150, 50, 100, 100, 150, 50, 25,25, 100, 300, 120, 100, 
160, 200), 
stringsAsFactors = FALSE)

当我在代码上运行Function fillLevel时

fillLevel <- function(x, width = 3, fill = "m"){ sp <- split(x, substr(x, 1, 1)) sp <- lapply(seq_along(sp), function(i){ n <- nchar(sp[[i]]) if(all(n < 3)){ j <- which(n == max(n)) sp[[i]][j] <- gsub(" ", "m", formatC(sp[[i]][j], width = -3)) } sp[[i]] }) unname(unlist(sp))}

发生一些奇怪的事情 m.df3 <- df3 %>% mutate(m.prodcat = fillLevel(Product cat.)) 特别是,m.prodcat类别与product cat.不对应。 例如,美国向欧盟出口产品类别的更改。 2到m.prodcat 1 ,来自产品cat。 21到m.prodcat 11等。还有许多其他不匹配的地方。

有人知道原因吗?非常感谢您的帮助

3 个答案:

答案 0 :(得分:2)

在您发表评论后,这是我对问题的理解的基本R方法。
我创建了另一个具有两行额外数据集的数据集,目的是使代码上升到聚合的第二层。

df2 <- data.frame("Reporter" = c("USA", "USA", "USA", "USA", "USA","USA", "USA", "USA"),
                 "Partner" = c( "EU", "EU","EU","EU", "EU","EU","EU", "EU"), 
                 "Product cat." = c("1", "11", "111", "122", "12", "2", "3", "31"), 
                 "Year" = c(1970, 1970, 1970, 1970, 1970, 1970, 1970, 1970), 
                 "trade value" = c( 100, 50, 25, 5, 40, 220, 120, 20), stringsAsFactors = FALSE)


fillLevel <- function(x, width = 3, fill = "m"){
  sp <- split(x, substr(x, 1, 1))
  sp <- lapply(seq_along(sp), function(i){
    n <- nchar(sp[[i]])
    if(all(n < 3)){
      j <- which(n == max(n))
      sp[[i]][j] <- gsub(" ", "m", formatC(sp[[i]][j], width = -3))
    }
    sp[[i]]
  })
  unname(unlist(sp))
}

fillLevel(df$Product.cat.)
#[1] "1"   "11"  "111" "122" "12"  "2mm"

fillLevel(df2$Product.cat.)
#[1] "1"   "11"  "111" "122" "12"  "2mm" "3"   "31m"

现在将函数的结果分配给您想要的任何值,无论是新列还是原始列。

答案 1 :(得分:2)

这里是str_pad

的一个选项
library(dplyr)
library(stringr)
df %>% 
  mutate(Product.cat. = str_pad(Product.cat., width = 3, pad = "m", side = "right"))
#  Reporter Partner Product.cat. Year trade.value
#1      USA      EU          1mm 1970         100
#2      USA      EU          11m 1970          50
#3      USA      EU          111 1970          25
#4      USA      EU          122 1970           5
#5      USA      EU          12m 1970          40
#6      USA      EU          2mm 1970         220

答案 2 :(得分:0)

另一种方法是使用stri_pad_rigth()中的stringi

library(stringi)
library(dplyr)

mutate(df, Product.cat. = stri_pad_right(Product.cat., 3, 'm'))

  Reporter Partner Product.cat. Year trade.value
1      USA      EU          1mm 1970         100
2      USA      EU          11m 1970          50
3      USA      EU          111 1970          25
4      USA      EU          122 1970           5
5      USA      EU          12m 1970          40
6      USA      EU          2mm 1970         220

readr::str_pad()在后​​台使用stringi::stri_pad_*()函数:

> str_pad
function (string, width, side = c("left", "right", "both"), pad = " ") 
{
    side <- match.arg(side)
    switch(side, left = stri_pad_left(string, width, pad = pad), 
        right = stri_pad_right(string, width, pad = pad), both = stri_pad_both(string, 
            width, pad = pad))
}
<bytecode: 0x566a028>
<environment: namespace:stringr>