当 id 重复时,如何使用 id 变量作为最终值进行重塑

How to reshape using id variable as final value, when id has duplicates

为了在 R 中做到这一点,我付出了很多努力。我的数据看起来像这样(真实数据有超过 120k 个观察值):

df <- data.frame(
  Input = c(1,2,3,4,4,5,1,3,4),
  Output = c(91,91,91,91,91,91,92,92,92)
)

df
  Input Output
1     1     91
2     2     91
3     3     91
4     4     91
5     4     91
6     5     91
7     1     92
8     3     92
9     4     92

数字是实物代码。这里的关键是产品 91 使用 5 个输入,而产品 92 仅使用 3 个,并且 91 中有重复项(两个 4)

我希望数据框的输出为列名,输入为值(忽略重复项):

       91         92
       1          1
       2          NA
       3          3
       4          4
       5          NA

所以,我使用

从长到宽进行了整形
df2 <- reshape(df, idvar = "Input", v.names = "Output", timevar = "Output", direction = "wide", sep = "_")

这会花费很多时间,而且无法使其他代码 from this post 工作。它产生一个中间步骤:

  Input Output_91 Output_92
1     1        91        92
2     2        91        NA
3     3        91        92
4     4        91        92
5     5        91        NA

然后,我所要做的就是用第一列替换每个输出列,除非 NA。我一次可以为一列轻松完成此操作。例如:

df2$Output_92[!is.na(df2$Output_92)] <- df2$Input[!is.na(df2$Output_92)]

我一直在尝试对列进行循环以遍历所有 2+ 列,模仿上述命令。类似于:

for(i in colnames(df2)){
        df2[!is.na(i)][i] <- df2$Input[!is.na(i)][i]
      }

这不起作用。

所以,原则上我只在这个循环中需要帮助(问题标题)。但是非常欢迎优化重塑的提示,或者更简单的方法来完成整个事情。

UPDATE:我意识到重复是我的问题的关键,因为没有这些,链接 post 中的标准解决方案工作正常。相应地更新了问题。下面的答案有助于解决 ID 重复的情况。

如果给定输出有重复输入,假设您不关心对它们进行计数或以任何不同方式对待它们,那么下面的所有方法都可以通过将 df 替换为 unique(df) 来工作。 (如果愿意,也可以使用 dplyr::distinct。)

一旦你解决了唯一性问题,那么......这就是从长到宽的“公正”reshaping/pivoting。

基础 R

stats::reshape 有点难用,它需要一些不是唯一存在的东西。例如,它要求 idvarv.names 变量是唯一列(所以我们复制 Input):

df$Input2 <- df$Input
out <- reshape(unique(df), idvar = "Input", v.names = "Input2", timevar = "Output", direction = "wide")
out
#   Input Input2.91 Input2.92
# 1     1         1         1
# 2     2         2        NA
# 3     3         3         3
# 4     4         4         4
# 6     5         5        NA
names(out) <- gsub("Input2\.", "", names(out))
# out[,-1]
  91 92
# 1  1  1
# 2  2 NA
# 3  3  3
# 4  4  4
# 6  5 NA

整理器

(重复列上的同上。)

library(dplyr)
library(tidyr) # pivot_wider
df %>%
  distinct() %>%
   mutate(Input2 = Input) %>%
   pivot_wider(Input, names_from = "Output", values_from = "Input2") %>%
   select(-Input)
# # A tibble: 5 x 2
#    `91`  `92`
#   <dbl> <dbl>
# 1     1     1
# 2     2    NA
# 3     3     3
# 4     4     4
# 5     5    NA

data.table

此处不需要"Input2"

library(data.table)
dcast(unique(as.data.table(df)), Input ~ Output, value.var = "Input")[,-1]
#       91    92
#    <num> <num>
# 1:     1     1
# 2:     2    NA
# 3:     3     3
# 4:     4     4
# 5:     5    NA

在这里,unique可以进入内部或外部as.data.table(.),你的选择。

平凡地,因为我对重复不感兴趣,我只需要事先删除它们,之后 this post 中的代码就可以正常工作了。

删除 df <- df[!duplicated(df[c("Output","Input")]),]