如何将自定义格式字符串解析为R DataFrame的单行多列?
问题:解析R DataFrame中类JSON格式的Stage列为单行多列
我正在处理一个包含Stage列的R DataFrame,该列采用类JSON的自定义字符串格式。我希望将其中的键值对解析为单独列,值对应原数据的同一行。
我尝试了正则提取、拆分及透视等方法,代码如下:
library(stringr) library(dplyr) library(tidyr) # Sample dataframe df <- data.frame(Stage = c("[{stage_type drive} {guid 1234a-f3f0-123b-c123d-e123456789f} {event_start_timestamp_ms 1684469450000} {event_end_timestamp_ms <nil>} {stage_number <nil>} {active true}]")) # Extract key-value pairs using regular expressions pattern <- "\\{(.*?)\\s(.*?)\\}" df$pairs <- str_extract_all(df$Stage, pattern) # Remove empty strings from pairs column df$pairs <- lapply(df$pairs, function(x) x[x != ""]) # Split the pairs into separate columns df_split <- df %>% unnest(pairs) %>% separate(pairs, into = c("key", "value"), sep = " ", remove = FALSE) %>% mutate(value = ifelse(value == "", NA, value)) %>% mutate(key = gsub('[^A-Za-z0-9_]','', key), value = gsub('[^A-Za-z0-9_-]','', value) ) %>% select(-Stage) df_pivot <- df_split %>% pivot_wider(names_from = key, values_from = value) %>% select(-c(key, pairs))
但最终得到6行数据,而我期望的是如下单行多列格式:
| stage_type | guid | event_start_timestamp_ms | event_end_timestamp_ms | stage_number | active |
|---|---|---|---|---|---|
| drive | 1234a-f3f0-123b-c123d-e123456789f | 1684469450000 | nil | nil | true |
请问我的思路是否有误?该如何调整实现目标格式?
解决方案
你的思路方向是对的,问题出在**pivot_wider前没有保留原数据的行标识**,导致每个键值对被当成独立行处理,最终透视后出现重复行。另外正则和数据清理环节也可以优化,具体调整如下:
修正步骤:
- 给原始数据添加行ID,确保透视时能将同一行的键值对聚合到一起
- 优化正则提取,更精准匹配键值对,避免误拆分带特殊符号的字段值
- 简化数据清理逻辑,正确处理
<nil>这类特殊值
修正后的代码:
library(stringr) library(dplyr) library(tidyr) # 样本数据(补全原代码的语法错误) df <- data.frame(Stage = c("[{stage_type drive} {guid 1234a-f3f0-123b-c123d-e123456789f} {event_start_timestamp_ms 1684469450000} {event_end_timestamp_ms <nil>} {stage_number <nil>} {active true}]")) # 1. 添加行ID,用于后续聚合同一原始行的键值对 df <- df %>% mutate(row_id = row_number()) # 2. 提取键值对:优化正则,精准匹配{key value}格式 df$pairs <- str_extract_all(df$Stage, "\\{([a-z_]+)\\s+([^}]+)\\}") # 3. 展开键值对并拆分出key和value df_split <- df %>% unnest(pairs) %>% mutate( key = str_match(pairs, "\\{([a-z_]+)\\s+")[,2], value = str_match(pairs, "\\s+([^}]+)\\}")[,2] ) %>% # 处理<nil>为指定的"nil"值 mutate(value = ifelse(value == "<nil>", "nil", value)) %>% select(row_id, key, value) # 4. 透视成宽表,按row_id聚合所有键值对到同一行 df_pivot <- df_split %>% pivot_wider(names_from = key, values_from = value) %>% select(-row_id) # 移除临时行ID # 查看最终结果 print(df_pivot)
代码说明:
- 行ID的作用:
row_id是核心,它让pivot_wider知道哪些键值对属于同一原始行,避免拆分后分散成多行 - 优化正则:
\\{([a-z_]+)\\s+([^}]+)\\}专门匹配由字母下划线组成的键,以及大括号内直到末尾的所有内容作为值,不会拆分像guid这类带连字符的字段 - 值处理:直接将
<nil>替换为"nil",保留其他值的原始格式,避免过度正则清理破坏数据
内容的提问来源于stack exchange,提问作者matt
相关产品推荐
相关产品推荐

