在保留类/数据类型信息的同时转置数据帧

时间:2016-02-05 12:31:33

标签: r excel dataframe xlsx transpose

TL;博士

如何使用不同类别的列向量转换数据框(一列为character,下一列为numeric,另一列为logical等),方式为: 保留类/数据类型信息?

示例数据:

mydata <- data.frame(
  col0 = c("row1", "row2", "row3"),
  col1 = c(1, 2, 3),
  col2 = letters[1:3],
  col3 = c(TRUE, FALSE, TRUE)
)

这里还有一个xlsx文件,其中包含两个数据方向的示例:https://github.com/rappster/stackoverflow/blob/master/excel/row-and-column-based-data.xlsx

问题

一个简单的t()或更多涉及的例程(如this post中建议的例程)很棒,但不保留类信息或原始数据框的列。我也知道类data.frame从未打算在其列中存储混合类信息。

但是,至少我希望能够尽可能简单地“颠倒”data.frame的方式:将视角置于而不是专栏透视。即,行向量中的所有元素都需要属于同一个类,而类可以在列向量之间有所不同。

上下文

我经常在人们习惯用水平(“变量在行中”)代替时间序列数据的项目中工作,而不是垂直(我们在R中习惯的“变量是列中的”方向(而且,恕我直言,也使更多更有意义)。

更重要的是,他们广泛使用MS Excel。我需要通过XLConnect和/或openxlsx将公式直接从R写入文件,以“宽格式”和“更新现有Excel文件”读取数据(而不是能够在R中进行我的计算,然后只是转储最终结果在Excel文件中)。

虽然我经常试图告诉他们使用这样的定位意味着跨越语言/工具的既定标准(至少对于R和MS Excel来说是这样),但他们不太可能会切换。所以我必须以某种方式解决这个问题。

目前的方法

所以我虽然保留了基础list,但尽可能让它“外观和感觉”像data.frame。它有效,但非常复杂。我认为可能会有更聪明的解决方案。

功能定义:

transpose <- function (
  x,
  col = character(),
  rnames_or_col = c("col", "rnames")
) {
  rnames_or_col <- match.arg(rnames_or_col, c("col", "rnames"))

  ## Buffering column names //
  cnames <- if (length(col)) {
    x[[col]]
  } else {
    make.names(1:nrow(x))
  }

  ## Removing anchoring column //
  if (inherits(x, "data.table")) {
    x <- as.data.frame(x, stringsAsFactors = FALSE)
  }
  ## I don't like this part. Any suggestions on how a) build on top of existing
  ## data.table functionality b) the easiest way to make a data.table behave
  ## like a data.frame when indexing (remove operation below will yield
  ## "undesired" results from a data.frame perspective; it's fine in from
  ## data.table's perspective/paradigm of course)
  if (length(col)) {
    x <- x[ , -which(names(x) == col)]
  }

  ## Buffer classes //
  classes <- lapply(x, class)

  ## Buffer row names //
  rnames <- names(x)

  ## Listify //
  x <- lapply(as.list(x), function(row) {
    df <- do.call(data.frame, list(as.list(row), stringsAsFactors = FALSE))
    names(df) <- cnames
    df
  })
  names(x) <- rnames

  ## Actual row names or row names as first column //
  if (rnames_or_col == "col") {
    x <- lapply(x, function(ii) {
      data.frame(variable = row.names(ii), ii,
        stringsAsFactors = FALSE, row.names = NULL, check.names = FALSE)
    })
  }

  ## Class //
  class(x) <- c("df_transposed", class(x))

  x
}

打印方式:

print.df_transposed <- function(object) {
  cat("df_transposed: \n")
  out <- do.call(rbind, object)
  rownames(out) <- NULL
  print(out)
}

Getter和setter方法:

"[<-.df_transposed" <- function(x, i, j, value) {
  x[[i]][ , j] <- value
  x
}

"[.df_transposed" <- function(x, i, j, drop = FALSE) {
# foo <- function(x, i, j, drop = FALSE) {
  has_i <- !missing(i)
  has_j <- !missing(j)
  cls <- class(x)
  scope <- if (has_i) {
    i
  } else {
    1:length(x)
  }
  out <- lapply(unclass(x)[scope], function(ii) {
    nms <- names(ii)

    if (has_j) {
      tmp <- ii[ , j, drop = drop]
      names(tmp) <- nms[j]
      ## --> necessary due to `check.names` missing for `[.data.frame` :-/
      tmp
    } else {
      ii
    }
  })
  class(out) <- cls
  out
}

班级职能:

class2 <- function(x) {
  sapply(x, function(ii) {
    value <- if ("variable" %in% names(ii)) {
      unlist(ii[, -1])
    } else {
      unlist(ii)
    }
    class(value)
  })
}

应用

示例数据:

mydata <- data.frame(
  col0 = c("row1", "row2", "row3"),
  col1 = c(1, 2, 3),
  col2 = letters[1:3],
  col3 = c(TRUE, FALSE, TRUE)
)

实际转置和打印方法:

> (df_t <- transpose(mydata, col = "col0"))
df_transposed: 
  variable row1  row2 row3
1     col1    1     2    3
2     col2    a     b    c
3     col3 TRUE FALSE TRUE
> (df_t2 <- transpose(mydata, col = "col0", rnames_or_col = "rnames"))
df_transposed: 
     row1  row2 row3
col1    1     2    3
col2    a     b    c
col3 TRUE FALSE TRUE

打印未打开的对象:

> unclass(df_t)
$col1
  variable row1 row2 row3
1     col1    1    2    3

$col2
  variable row1 row2 row3
1     col2    a    b    c

$col3
  variable row1  row2 row3
1     col3 TRUE FALSE TRUE

> unclass(df_t2)
$col1
     row1 row2 row3
col1    1    2    3

$col2
     row1 row2 row3
col2    a    b    c

$col3
     row1  row2 row3
col3 TRUE FALSE TRUE

班级查询:

> class2(df_t)
       col1        col2        col3 
  "numeric" "character"   "logical"     

索引:

> dat_t[1, ]
df_transposed: 
  variable row1 row2 row3
1        1    1    2    3
> dat_t[, 1]
df_transposed: 
  variable
1        1
2        1
3        1
> 
> dat_t[1, 2]
df_transposed: 
     row1
col1    1
> dat_t[2, 3]
df_transposed: 
     row2
col2    b
> 
> dat_t[1:2, ]
df_transposed: 
  variable row1 row2 row3
1        1    1    2    3
2        1    a    b    c
> dat_t[, 1:3]
df_transposed: 
  variable row1  row2
1        1    1     2
2        1    a     b
3        1 TRUE FALSE
> 
> dat_t[c(1, 3), 2:4]
df_transposed: 
     row1 row2 row3
col1    1    2    3
col3    1    0    1

0 个答案:

没有答案