我有一个包含多个字段的大型数据集,其值由空格分隔。然后,将这些字段组合在一起以形成一条记录,并且每条记录可以具有可变长度的子项(带有制表符)。
文件内容看起来像这样:
company Samsung
type private
based South Korea
company Harman International
type private
based United States
industry Electronics
company JBL
type subsidiary
based United States
industry Audio
company Amazaon
type public
based United States
industry Cloud computing, e-commerce, artificial intelligence, consumer electronics
我想在存储这些记录的同时保持层次结构,并选择进行快速搜索和访问每条记录的方式。
到目前为止,我想出了这种方法:
# reading file from the source
path <- "/path/to/file.txt"
content <- readLines(path, warn = F)
# replaces , with ; so it does not translate it as a separator in next step
content <- gsub(",", ";", content)
# creating list of fields and value
contentList <- read.csv(text=sub(" ", ",", content), header=FALSE)
# replacing ; with , to revert data in right format
contentList$V2 <- gsub(";", ",", contentList$V2)
经过以上步骤,contentList
如下所示:
在下一步中,我考虑使用一个函数来创建具有以下规则的列表:
\t
则将其添加到列表中(作为命名向量)\t
使其成为先前记录的子列表(如命名矢量)但是不知道如何在R中实现。
我应该如何实施呢?
还是有更好的方法来解决此问题,该问题可以快速执行搜索和访问值?
使用末尾“注释”中的内容,计算每个公司行开头的空格,并使用gsubfn将其替换为给出L2的级别编号。然后修剪掉前导空格后,用冒号L3替换每行的第一个空格。该文件现在为dcf格式,因此请使用read.dcf读取它以得到L4。
现在生成一个lv变量,将级别号指定为数字,并为每一行生成顺序的数字ID。计算给定父代的父代ID,然后使用到目前为止已计算的内容构造一个数据框。树的整体根由0表示。从DF生成图的边列表e,并将其转换为igraph。从中生成简单路径,并创建具有列路径,公司,类型,基础和行业的数据帧DF2,以使每一行代表根以外的一个节点。
如果您愿意,可以将lv和parent添加到我们计算出的数据帧中,但由于您可能不需要它们而未添加。
下面的假设是每个缩进为4个空格。
对级别可以走多深没有限制。
我们可以使用数据框操作搜索DF2,以查找各种基于文本的查询,例如
subset(DF2, grepl("Samsung", paths)) # Samsung and its descendents
或者我们可以使用igraph函数对g进行图形查询,例如
max(length(get.diameter(g))) - 1 # max depth not counting root
或者我们可以使用data.tree函数进行查询
dt$height - 1 # max depth not counting root
代码如下。
library(gsubfn)
content <- readLines(textConnection(Lines))
L2 <- gsubfn("( *)company", ~ paste0("level ", nchar(x) / 4L + 1L, "\ncompany"), content)
L3 <- sub(" ", ":", trimws(readLines(textConnection(L2))))
L4 <- read.dcf(textConnection(L3))
lv <- as.numeric(L4[, 1])
id <- seq_along(lv)
company <- L4[, "company"]
parent <- sapply(id, function(i) c(tail(which(lv[1:i] < lv[i]), 1), 0)[1])
DF <- data.frame(id = company[id], parent = c("0", company)[parent+1],
level = lv, L4[, -1], stringsAsFactors = FALSE)
e <- with(DF, cbind(parent, id))
现在我们有了边缘列表,我们可以创建一个igraph并使用该程序包对其进行处理。
library(igraph)
g <- graph_from_edgelist(e)
p <- all_simple_paths(g, "0")
paths <- sapply(p, function(x) paste(names(x), collapse = "/"))
DF2 <- data.frame(paths, L4[, -1], stringsAsFactors = FALSE)
DF2
提供一个path列,后跟每个节点的属性:
paths company type based industry
1 0/Samsung Samsung private South Korea <NA>
2 0/Samsung/Harman International Harman International private United States Electronics
3 0/Samsung/Harman International/JBL JBL subsidiary United States Audio
4 0/Amazaon Amazaon public United States Cloud computing, e-commerce, artificial intelligence, consumer electronics
我们可以这样绘制图形:
plot(g, layout = layout_as_tree(g))
我们还可以使用data.tree及其许多功能来处理此问题:
library(data.tree)
library(DiagrammeR)
dt <- FromDataFrameNetwork(DF)
print(dt, "type", "based", "industry")
给予:
levelName type based industry
1 0
2 ¦--Samsung private South Korea
3 ¦ °--Harman International private United States Electronics
4 ¦ °--JBL subsidiary United States Audio
5 °--Amazaon public United States Cloud computing, e-commerce, artificial intelligence, consumer electronics
我们可以如下绘制或转换数据树数据
plot(dt) # plot in browser
ToListSimple(dt) # convert to nested list
ToListExplicit(dt) # similar but children in children component
我们可以像这样重复创建内容:
Lines <- "
company Samsung
type private
based South Korea
company Harman International
type private
based United States
industry Electronics
company JBL
type subsidiary
based United States
industry Audio
company Amazaon
type public
based United States
industry Cloud computing, e-commerce, artificial intelligence, consumer electronics"
content <- readLines(textConnection(Lines))
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句