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

将长格式DataFrame转为宽格式以去除重复Person.Id记录

将重复Person.Id的DataFrame转换为宽格式

问题描述

你有一个包含重复Person.Id的DataFrame,每个居住过的城市对应一行记录,需要将其转换为宽格式,用二进制(1/0)标记用户是否居住过某城市,同时保留Current_Patient、DOB等唯一信息列,消除重复的Person.Id。

原始DataFrame:

> dput(df)
structure(list(Person.Id = c(123L, 345L, 345L, NA), City_lived = c("NY", 
"NY", "Boston", NA), Current_Patient = c("Yes", "Yes", "Yes", NA), DOB = c("11/20/97", "10/10/92", "10/10/92", NA)), class = "data.frame", row.names = c(NA, 
-4L))

期望输出:

> dput(df2)
structure(list(Person.Id = c(123L, 345L), City_lived_Boston = c(0L, 
1L), City_lived_NY = c(1L, 1L), Current_Patient = c("Yes", 
"Yes"), DOB = c("11/20/97", "10/10/92")), class = "data.frame", row.names = c(NA, -2L))

解决方案

方法1:使用tidyverse的pivot_wider(推荐)

pivot_wider是tidyverse生态中专门用于长转宽的函数,语法清晰易读:

library(tidyverse)

# 加载原始数据
df <- structure(list(Person.Id = c(123L, 345L, 345L, NA), 
                     City_lived = c("NY", "NY", "Boston", NA), 
                     Current_Patient = c("Yes", "Yes", "Yes", NA), 
                     DOB = c("11/20/97", "10/10/92", "10/10/92", NA)), 
                class = "data.frame", row.names = c(NA, -4L))

# 转换为宽格式
df2 <- df %>%
  # 过滤掉Person.Id为NA的无效行
  filter(!is.na(Person.Id)) %>%
  pivot_wider(
    # 指定唯一标识列(每个Person.Id对应的唯一信息)
    id_cols = c(Person.Id, Current_Patient, DOB),
    # 将City_lived的取值转为列名
    names_from = City_lived,
    # 给新列添加前缀,匹配期望格式
    names_prefix = "City_lived_",
    # 基于City_lived列生成值
    values_from = City_lived,
    # 用length判断是否存在该城市(存在则标记为1)
    values_fn = ~ifelse(length(.x) > 0, 1L, 0L),
    # 不存在的城市标记为0
    values_fill = 0L
  )

# 查看结果
dput(df2)

方法2:使用reshape2的dcast

如果你习惯使用传统的reshape2包,也可以用dcast实现:

library(reshape2)

# 加载原始数据
df <- structure(list(Person.Id = c(123L, 345L, 345L, NA), 
                     City_lived = c("NY", "NY", "Boston", NA), 
                     Current_Patient = c("Yes", "Yes", "Yes", NA), 
                     DOB = c("11/20/97", "10/10/92", "10/10/92", NA)), 
                class = "data.frame", row.names = c(NA, -4L))

# 过滤无效行
df_filtered <- df[!is.na(df$Person.Id), ]

# 转宽格式
df2 <- dcast(
  df_filtered, 
  Person.Id + Current_Patient + DOB ~ City_lived, 
  fun.aggregate = length, 
  value.var = "City_lived", 
  fill = 0
)

# 给城市列添加前缀,匹配期望格式
colnames(df2) <- ifelse(colnames(df2) %in% c("Person.Id", "Current_Patient", "DOB"), 
                        colnames(df2), paste0("City_lived_", colnames(df2)))

# 查看结果
dput(df2)

关键说明

  1. 过滤无效行:原始数据中存在Person.Id为NA的行,这部分数据无意义,先通过filter或索引过滤掉。
  2. 唯一标识列:Person.Id、Current_Patient、DOB是每个用户的唯一信息,必须作为id_cols(或dcast的行变量),确保转换后每个Person.Id只保留一行。
  3. 二进制标记:通过values_fn = length或~ifelse(length(.x) > 0, 1L, 0L)实现“是否居住过某城市”的标记,存在则为1,不存在则为0。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.30 01:48:12