You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何将含重复值的长格式DataFrame转换为二进制DataFrame?

处理长格式DataFrame转二进制宽格式时的重复值问题

我现在需要把长格式的DataFrame转换成二进制标记的宽格式,但遇到了同一用户对应同一个值重复出现的情况,不知道该怎么处理。

我的示例长格式DataFrame如下:

d_long <- data.frame( 
  nameid = c("sally","sally","sally", "sally","Robert","annie","annie","annie"), 
  value = c("product1","ra","ent","ra","ra","ra","product1","product1")
)

对应的数据展示:

nameid value 
1 sally product1 
2 sally ra 
3 sally ent 
4 sally ra 
5 Robert ra 
6 annie ra 
7 annie product1 
8 annie product1

我想要的预期输出是这样的二进制宽格式:

d_exist <- data.frame(
  nameid = c("sally","Robert","annie"), 
  product1 = c(1,0,1), 
  ra = c(1,1,1), 
  ent = c(1,0,0)
)

对应结果:

nameid product1 ra ent 
1 sally 1 1 1 
2 Robert 0 1 0 
3 annie 1 1 0

我尝试了下面的代码,但出现了报错:

d_long %>% 
  group_by(nameid, value) %>% 
  mutate(count = n()) %>% 
  ungroup() %>% 
  spread(value, count, fill = 0) %>% 
  as.data.frame()

报错信息:

Error: Duplicate identifiers for rows (7, 8), (2, 4)

想请教一下,仅使用 d_long[!duplicated(d_long), ] 这个方法是否可行?


首先,直接用 d_long[!duplicated(d_long), ] 是完全可行的!这个方法能先把nameid和value的重复组合去掉,只保留每组的唯一记录,之后再转宽格式就不会有重复标识符的问题了。

你可以试试这样写:

# 先去重,再转宽格式
d_long %>%
  distinct(nameid, value) %>%  # 这行和d_long[!duplicated(d_long), ]效果一致,更符合tidyverse风格
  mutate(flag = 1) %>%
  spread(value, flag, fill = 0) %>%
  as.data.frame()

或者用你提到的去重方式:

d_long[!duplicated(d_long), ] %>%
  mutate(flag = 1) %>%
  spread(value, flag, fill = 0) %>%
  as.data.frame()

这两种方式都能得到你想要的二进制标记结果——毕竟我们只需要标记用户是否拥有某个value,不管重复出现多少次,都只记为1。

另外,如果你想用更现代的tidyverse函数,也可以用pivot_wider替代spread(spread已经被软弃用了),写法更直观:

d_long %>%
  distinct(nameid, value) %>%
  pivot_wider(
    names_from = value,
    values_from = value,
    values_fn = ~1,
    values_fill = 0
  )

至于你之前报错的原因,是因为group_by+mutate(count = n())之后,原来的重复行依然存在(只是多了count列),比如sally的"ra"有两行,annie的"product1"有两行,这时候spread会因为同一nameid下有重复的行而报错,因为它不知道该怎么处理这些重复的标识符。而先去重之后,每个nameid+value的组合只有一行,转宽格式就不会有冲突了。

还有一种更简洁的基础R方法,用table函数直接统计频次,再转成DataFrame并处理二进制:

tab <- table(d_long$nameid, d_long$value)
# 把频次转换成二进制(只要出现过就为1)
tab[tab > 0] <- 1
# 转成DataFrame并保留nameid列
as.data.frame.matrix(tab) %>%
  rownames_to_column("nameid")

这个方法也能快速得到你想要的结果,而且代码量很少。

总结一下:d_long[!duplicated(d_long), ]完全可行,是解决这个问题的有效方法,你也可以根据自己的习惯选择tidyverse风格的distinct或者基础R的table方法。


内容的提问来源于stack exchange,提问作者user8831872

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.28 07:18:21