r - R:将任意连接变量名称和值的向量转换为单个数据框
问题描述
我有一个包含两列和多行的数据框。
第一列是一个字符向量,其中每个元素 P 是一个字符串,它用逗号连接多个 (K) 字符串。K 事先是未知的,并且可以跨行变化,例如第一行 K = 5,第二行 K = 3。连接起来的值在各行之间可能相同,也可能不同,尽管它们不会在一行内重复。我们可以称这些“变量名”。
第二列——我们可以称之为“变量值”——是一个字符向量,其中每个元素也是一个用逗号连接 K 个字符串的字符串。重要的是,连接的字符串数量与变量名称的数量相同。换句话说,变量名称列包含一个包含变量名称的字符串,变量值列包含与该行的变量名称对应的值。
这是我的数据的一个最小示例。请注意, eg 中的子字符串数var_names[i]
等于 in 中的相同数,values[i]
但不必等于var_names[j]
:
# Example data
data <-
data.frame(
var_names = c(
paste("a", "b", "c", "e", "j", sep = ","),
paste("d", "a", "f", sep = ","),
paste("f", "k", "b", "a", sep = ",")
),
values = c(
paste("212", "12", "sfd", "3", "1", sep = ","),
paste("fds", "23", "g", sep = ","),
paste("df", "sdf", "w2", "w", sep = ",")
),
stringsAsFactors = FALSE
)
鉴于这些数据,我正在尝试创建一个数据框,其中每个唯一值var_names
都是列名,并且每列的值基于values
数据中每一行的相应索引。具体来说,我希望制作:
data.frame(a = c("212","23","w"),
b = c("12",NA,"w2"),
c = c("sfd",NA,NA),
d = c(NA,"fds",NA),
e = c("3", NA, NA),
f = c(NA, "g", "df"),
j = c("1"," NA, NA),
k = c(NA,NA,"sdf"))
我能够使用以下内容制作我想要的东西。但是,我想知道是否有一些功能/包可以让我跳过其中一些步骤并更快地完成这项工作。目前,我创建了一个循环,为每一行生成整个数据框,然后将它们组合成一个数据框。我最初的想法是var_val
在我的代码中获取对象并用于tidyr::pivot_wider()
生成每一行的数据框,但由于规范错误,这不起作用。
# Split variable names and values into a list
# where each element is a row's values/names
vars_name_l <- strsplit(data$var_names, split = ",")
values_l <- strsplit(data$values, split = ",")
# Initialize a list to store each row's
# data frame
combined <- list()
# Loop through each row's data and generate a
# list of data frames
for (i in 1:length(nrow(data))) {
# Get a row's variable names and values into
# a data frame.
var_val <- data.frame(var_names = vars_name_l[[i]],
values = values_l[[i]],
stringsAsFactors = FALSE)
# Create an empty data frame then add variable
# names and the values for the variables, store in
# our list
df <- as.data.frame(matrix(numeric(), nrow = 0, ncol = length(var_val$var_names)))
colnames(df) <- var_val$var_names
df[1, ] <- var_val$values
combined[[i]] <- df
}
# Collapse list to a single data frame, rearrange
result <- bind_rows(combined)
result[ ,order(colnames(result))]
解决方案
我们可以bind_rows
轻松做到这一点
library(dplyr)
bind_rows(do.call(Map, c(f = setNames, lapply(unname(data)[2:1], strsplit, ","))))
# A tibble: 3 x 8
# a b c e j d f k
#* <chr> <chr> <chr> <chr> <chr> <chr> <chr> <chr>
#1 212 12 sfd 3 1 <NA> <NA> <NA>
#2 23 <NA> <NA> <NA> <NA> fds g <NA>
#3 w w2 <NA> <NA> <NA> <NA> df sdf
或者它可以是
bind_rows(do.call(Map, c(f = function(x, y)
setNames(as.list(x), y), lapply(unname(data)[2:1], strsplit, ","))))
或者另一个选项unnest_wider
来自tidyr
library(tidyr)
library(purrr)
data %>%
mutate_all(strsplit, ",") %>%
transmute(new = map2(values, var_names, ~ set_names(as.list(.x), .y))) %>%
unnest_wider(c(new))
# A tibble: 3 x 8
# a b c e j d f k
# <chr> <chr> <chr> <chr> <chr> <chr> <chr> <chr>
#1 212 12 sfd 3 1 <NA> <NA> <NA>
#2 23 <NA> <NA> <NA> <NA> fds g <NA>
#3 w w2 <NA> <NA> <NA> <NA> df sdf
或使用rbindlist
fromdata.table
library(data.table)
rbindlist(do.call(Map, c(f = function(x, y)
setNames(as.list(x), y), lapply(unname(data)[2:1], strsplit, ","))),
fill = TRUE)
# a b c e j d f k
#1: 212 12 sfd 3 1 <NA> <NA> <NA>
#2: 23 <NA> <NA> <NA> <NA> fds g <NA>
#3: w w2 <NA> <NA> <NA> <NA> df sdf
推荐阅读
- r - 如何在 R 中以 2 小时的间隔对时间戳列进行分类?
- flutter - Flutter:在某个值上更改圆形进度指示器的颜色
- bash - 如何在 Unix 中进行索引到索引值的比较
- java - JPA - 一对多与连接表
- react-native - React Native 显示所有 RSS 项目
- c - 在检查新行时使用 fscanf 从文件中填充结构数组(反馈)
- laravel - 工作箱服务人员问题
- laravel - 方法 Illuminate\Database\Eloquent\Collection
- postgresql - 识别与 Redshift(或 Postgresql)中的条件匹配的类型
- python - 在 python 中使用 pandas 进行数据分帧期间将 HTTP 时间戳转换为标准格式的最佳实践是什么?