根据不同的列重塑数据

Reshaping data based on different columns

我有一个名为 '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中,Category列有类别,即输入数据中的列名。然后来自 country 列和 Male 列的国家将在输入中具有来自 Male 列的值。

与输出数据集 2 类似,Category 和 Country 保持不变,但第 3 列 Actuals 应具有输入中相应类别的值,即第 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)
      }

有什么不明白的地方请告诉我。

这是一个基本的 R 方法,它使用 stack 根据特定列(即 male/female、类别)转换为 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")