根据不同的列重塑数据

时间:2017-05-14 10:38:38

标签: r reshape2 tidyr

我有这个名为' inputdata'

Country Unknown Male Female Affected Male Female Unaffected Male Female
USA      200  120   80     130     80    50     70        40    30
AU       140  80    60     60      30    30     80        50    30

我将有两个输出数据集,它将如下所示,如您所见,输入数据集在此处有3个类别,如列名2,5,8中所述。

在输出1数据集中,“类别”列具有类别,即输入数据中的列名称。然后,来自country列和Male列的国家/地区将在输入中具有来自Male列的值。

类似地,在输出2数据集中,“类别”和“国家/地区”保持不变,但第3列“实际值”应具有输入中相应类别的值2,5,8。

这里的关键是输入数据集结构保持不变。

Output 1

Category    Country Male 
Unknown      USA     120  
Affected     USA     80
Unaffected   USA     40
.
.
.

Output 2

Category    Country Actuals
Unknown      USA     200   
Affected     USA     130 
Unaffected   USA     70 
.
.
.

所以我现在所做的是,使用for循环使用索引对输入数据集中的每个类别进行子集 -

例如,使用inputdata[,c(1,i)]和我的'i'变量将为3,6,9 for output 12,5,8 for output 2。然后创建一个数据框列表(每个类别一个),并将它们组合在一起用于每个输出。我只是想知道是否还有其他方法可以让它变得高效。

编辑: - 按要求添加我的代码,

for(i in seq(3, 9, by=3)) {
    if(!exists('mylist')) mylist <- NULL
    output1 <- inputdata[,c(1,i)]
    if(i==3) {
      output1$category <- 'unknown'
    } else if (i==6) {
      output1$category <- 'affected'
    } else
      output1$category <- 'unaffected'
    mylist <- c(mylist,output1)
    rm(output1)
  }


   for(i in seq(2, 8, by=3)) {
        if(!exists('mylist')) mylist <- NULL
        output2 <- inputdata[,c(1,i)]
        if(i==3) {
          output2$category <- 'unknown'
        } else if (i==6) {
          output2$category <- 'affected'
        } else
          output2$category <- 'unaffected'
        mylist <- c(mylist,output2)
        rm(output2)
      }

如果有任何不清楚的地方,请告诉我。

1 个答案:

答案 0 :(得分:0)

这是一个基础R方法,它使用stack根据特定列(即男/女,类别)转换为long。

#data frame of categories - You can further split of country if needed 
# by split(d1, d1$country)

d1 <- data.frame(stack(df[-1][c(T, F, F)]), country = df$Country, stringsAsFactors = FALSE)

#  values        ind country
#1    200    Unknown     USA
#2    140    Unknown      AU
#3    130   Affected     USA
#4     60   Affected      AU
#5     70 Unaffected     USA
#6     80 Unaffected      AU

#create a list with two data frames (male and female)
#To split by country again, then lapply(l1, function(i) split(i, i$country))

l1 <- lapply(c('Male', 'Female'), function(i) setNames(data.frame(d1$ind, 
                                                 stack(df[grepl(i, names(df))])[-2],
                                                    df$Country, stringsAsFactors = F), 
                                              c('category', i, 'country')))

#[[1]]
#    category Male country
#1    Unknown  120     USA
#2    Unknown   80      AU
#3   Affected   80     USA
#4   Affected   30      AU
#5 Unaffected   40     USA
#6 Unaffected   50      AU

#[[2]]
#    category Female country
#1    Unknown     80     USA
#2    Unknown     60      AU
#3   Affected     50     USA
#4   Affected     30      AU
#5 Unaffected     30     USA
#6 Unaffected     30      AU

数据

dput(df)
structure(list(Country = c("USA", "AU"), Unknown = c(200L, 140L
), Male = c(120L, 80L), Female = c(80L, 60L), Affected = c(130L, 
60L), Male.1 = c(80L, 30L), Female.1 = c(50L, 30L), Unaffected = c(70L, 
80L), Male.2 = c(40L, 50L), Female.2 = c(30L, 30L)), .Names = c("Country", 
"Unknown", "Male", "Female", "Affected", "Male.1", "Female.1", 
"Unaffected", "Male.2", "Female.2"), row.names = c(NA, -2L), class = "data.frame")