我有一个这样的df:
df1 <- data.frame(c(3,NA,5), c(NA, NA, 3), c(3, 2, NA))
names(df1) <- c('number1', 'number2', 'number3')
rownames(df1) <- c('siteA', 'siteB', 'siteC')
我想创建一个新的 df,其中行和列名称由非 NA 的值组合而成。结果 df 应如下所示:
df2 <- data.frame('number' = c('number1', 'number1', 'number2', 'number3', 'number3'),
'site' = c('siteA', 'siteC', 'siteC', 'siteA', 'siteB'))
如何尽可能高效地做到这一点? (我真正的 df 很大)
在矩阵或表格中,每个轴都可以有一个名称,该名称是标记该轴的字符串。将 df1 转换为矩阵 m 并将它们相加。
然后使用
as.data.frame.table
将其转换为长格式,并删除带有 NA 的行。 as.data.frame.table
将添加名为 Freq
的第三列,我们不需要它,因此仅选择前 2 列,并且由于问题将数字首先颠倒了提取的两列的顺序。
m <- as.matrix(df1)
names(dimnames(m)) <- c("site", "number")
m |>
as.data.frame.table() |>
na.omit() |>
subset(select = 2:1)
## number site
## 1 number1 siteA
## 3 number1 siteC
## 6 number2 siteC
## 7 number3 siteA
## 8 number3 siteB
m
看起来像这样。请注意暗名称。
m
## number
## site number1 number2 number3
## siteA 3 NA 3
## siteB NA NA 2
## siteC 5 3 NA
使用
tidyverse
的简单方法:
df1 %>%
rownames_to_column('site') %>%
pivot_longer(-site, names_to = 'number', values_to = 'value') %>%
filter(!is.na(value)) %>%
select(-value)
您也可以在此处使用
which()
。首先,您找到 data.frame 中没有缺失行的位置(不需要先将其转换为矩阵)并使用 arr.ind = TRUE
获取索引。这些索引是具有非 NA 值的数据的行和列。这样做的另一个好处是 row.names 将是原始 data.frame
的 row.names 。我将矩阵输出转换为具有正确变量名称的 data.frame,然后将列名称和行名称中的值分配给数字。
df2 <- which(!is.na(df1), arr.ind = TRUE)
df2 <- data.frame(number =colnames(df1)[df2[,2]] , site = row.names(df2))
乐趣基准:
transform_fn <- function(){
m <- as.matrix(df1)
names(dimnames(m)) <- c("site", "number")
m |>
t() |>
as.data.frame.table() |>
na.omit() |>
subset(select = 1:2)
}
which_fn <- function(){
df2 <- which(!is.na(df1), arr.ind = TRUE)
data.frame(number =colnames(df1)[df2[,2]] , site = row.names(df2))
}
tidyverse_fn <- function(){df1 %>%
rownames_to_column('site') %>%
pivot_longer(-site, names_to = 'number', values_to = 'value') %>%
filter(!is.na(value)) %>%
select(-value)
}
microbenchmark::microbenchmark(which_fn(),transform_fn(),tidyverse_fn(),
times = 1000)
我们可以尝试
expand.grid
+ dimnames
> rev(expand.grid(dimnames(df1)))[!is.na(unlist(df1)), ]
Var2 Var1
1 number1 siteA
3 number1 siteC
6 number2 siteC
7 number3 siteA
8 number3 siteB