将任意列拆分为融化的数据框
Split arbitrary column into melted data frame
我有一个 data.frame,其中包含结构化数据的丑陋列。每个列可以包含 1 到 40 个感兴趣的值。每个值都用 html 分隔符 "<br />"
分隔。提取的值是1.1
的形式,即一个整数一个句点,另一个整数。
如何将这些列分开并合并成不同的行?
我知道 lapply 和 tidy::separate 可能是可行的方法。但我还没有成功。所以求助
测试数据在这里:
testdata <- dget("http://pastebin.com/download.php?i=VS2cq2rB")
数据框包含两列:"id"
和"moduler"
。
我想要 "id" 和 "value"。最终结果应该是这样的。
"id", "value"
1, 1.1
1, 1.2
1, 1.3
1, 2.4
2, 1.1
2, 1.3
2, 3.3
这是我的最新作品 - 与我从 lapply 开始的地方相去甚远。
origdf <- data.frame()
#names(newdf) <- c("id", 'pnummer', 'moduler')
for (i in 1:nrow(hs)) {
newdf <- data.frame()
newdf[i, 'id'] <- hs[i, 'id']
newdf[i, 'pnummer'] <- hs[i, 'pnummer']
tmp <- unlist(strsplit(as.character(hs[i,'moduler']), "<br />", fixed=T))
for (m in 3:length(tmp)+3) {
newdf[i, m] <- tmp[m]
}
origdf <- dplyr::bind_rows(newdf, origdf)
}
这是一种可能的 data.table
方法。基本上我只是将 moduler
拆分为 "<br />"
或将 "<br />Installationsmontør"
拆分为 id
library(data.table)
setDT(testdata)[, .(value = unlist(strsplit(as.character(moduler),
"<br />|<br />Installationsmontør"))), by = id]
# id value
# 1: 2862 1.1
# 2: 2862 1.2
# 3: 2862 1.3
# 4: 2862 1.4
# 5: 2862 1.5
# ---
# 132: 2877 3.6
# 133: 2877 4.1
# 134: 2877 4.4
# 135: 2877 4.5
# 136: 2877 4.6
或与 splitstackshape
包类似
library(splitstackshape)
cSplit(testdata, splitCols = "moduler",
sep = "<br />|<br />Installationsmontør",
direction = "long", fixed = FALSE, stripWhite = FALSE)
我会尝试在一个简单的循环中使用 strsplit 函数:
newdata <- NULL
a <- 1
b <- 0
for (k in 1:length(testdata$moduler)) {
M <- unlist(strsplit(as.character(testdata$moduler[k]),"<br />|<br />Installationsmontør"))
b <- b + length(M)
newdata$moduler[a:b] <- M
newdata$id[a:b] <- testdata$id[k]
a <- b + 1
}
newdata <- as.data.frame(newdata)
这是另一个使用 tidyr
中的 unnest
的选项。我们使用 library(stringr)
中的 str_extract_all
提取数字部分 ([0-9.]+
)。输出是 list
。我们将 list
元素的名称设置为 'testdata' 和 unnest
的 'id' 列
library(tidyr)
library(stringr)
res <- unnest(setNames(lapply(str_extract_all(testdata$moduler, '[0-9.]+'),
as.numeric), testdata$id), id)
colnames(res)[2] <- 'value'
head(res)
# id value
#1 2862 1.1
#2 2862 1.2
#3 2862 1.3
#4 2862 1.4
#5 2862 1.5
#6 2862 1.6
dim(res)
#[1] 136 2
或者 base R
方法是在 list
中提取带有 regmatches/gregexpr
的数字元素,获取 list
元素的 length
lengths
,基于 'testdata' 复制 'id' 列,unlist
'lst' 并创建一个新的 'data.frame'.
lst <- lapply(regmatches(testdata$moduler, gregexpr('[0-9.]+',
testdata$moduler)), as.numeric)
res2 <- data.frame(id = testdata$id[rep(1:nrow(testdata), lengths(lst))],
value= unlist(lst))
我有一个 data.frame,其中包含结构化数据的丑陋列。每个列可以包含 1 到 40 个感兴趣的值。每个值都用 html 分隔符 "<br />"
分隔。提取的值是1.1
的形式,即一个整数一个句点,另一个整数。
如何将这些列分开并合并成不同的行?
我知道 lapply 和 tidy::separate 可能是可行的方法。但我还没有成功。所以求助
测试数据在这里:
testdata <- dget("http://pastebin.com/download.php?i=VS2cq2rB")
数据框包含两列:"id"
和"moduler"
。
我想要 "id" 和 "value"。最终结果应该是这样的。
"id", "value"
1, 1.1
1, 1.2
1, 1.3
1, 2.4
2, 1.1
2, 1.3
2, 3.3
这是我的最新作品 - 与我从 lapply 开始的地方相去甚远。
origdf <- data.frame()
#names(newdf) <- c("id", 'pnummer', 'moduler')
for (i in 1:nrow(hs)) {
newdf <- data.frame()
newdf[i, 'id'] <- hs[i, 'id']
newdf[i, 'pnummer'] <- hs[i, 'pnummer']
tmp <- unlist(strsplit(as.character(hs[i,'moduler']), "<br />", fixed=T))
for (m in 3:length(tmp)+3) {
newdf[i, m] <- tmp[m]
}
origdf <- dplyr::bind_rows(newdf, origdf)
}
这是一种可能的 data.table
方法。基本上我只是将 moduler
拆分为 "<br />"
或将 "<br />Installationsmontør"
拆分为 id
library(data.table)
setDT(testdata)[, .(value = unlist(strsplit(as.character(moduler),
"<br />|<br />Installationsmontør"))), by = id]
# id value
# 1: 2862 1.1
# 2: 2862 1.2
# 3: 2862 1.3
# 4: 2862 1.4
# 5: 2862 1.5
# ---
# 132: 2877 3.6
# 133: 2877 4.1
# 134: 2877 4.4
# 135: 2877 4.5
# 136: 2877 4.6
或与 splitstackshape
包类似
library(splitstackshape)
cSplit(testdata, splitCols = "moduler",
sep = "<br />|<br />Installationsmontør",
direction = "long", fixed = FALSE, stripWhite = FALSE)
我会尝试在一个简单的循环中使用 strsplit 函数:
newdata <- NULL
a <- 1
b <- 0
for (k in 1:length(testdata$moduler)) {
M <- unlist(strsplit(as.character(testdata$moduler[k]),"<br />|<br />Installationsmontør"))
b <- b + length(M)
newdata$moduler[a:b] <- M
newdata$id[a:b] <- testdata$id[k]
a <- b + 1
}
newdata <- as.data.frame(newdata)
这是另一个使用 tidyr
中的 unnest
的选项。我们使用 library(stringr)
中的 str_extract_all
提取数字部分 ([0-9.]+
)。输出是 list
。我们将 list
元素的名称设置为 'testdata' 和 unnest
library(tidyr)
library(stringr)
res <- unnest(setNames(lapply(str_extract_all(testdata$moduler, '[0-9.]+'),
as.numeric), testdata$id), id)
colnames(res)[2] <- 'value'
head(res)
# id value
#1 2862 1.1
#2 2862 1.2
#3 2862 1.3
#4 2862 1.4
#5 2862 1.5
#6 2862 1.6
dim(res)
#[1] 136 2
或者 base R
方法是在 list
中提取带有 regmatches/gregexpr
的数字元素,获取 list
元素的 length
lengths
,基于 'testdata' 复制 'id' 列,unlist
'lst' 并创建一个新的 'data.frame'.
lst <- lapply(regmatches(testdata$moduler, gregexpr('[0-9.]+',
testdata$moduler)), as.numeric)
res2 <- data.frame(id = testdata$id[rep(1:nrow(testdata), lengths(lst))],
value= unlist(lst))