[英]Stacking columns with similar names in R
我有一个CSV文件,无法更改其糟糕的格式(此处简化):
Inc,a_One,a_Two,a_Three,b_One,b_Two,b_Three
1,1,1.5,"5 Things",2,2.5,"10 Things"
2,5,5.5,"10 Things",6,6.5,"20 Things"
Inc,a_One,a_Two,a_Three,b_One,b_Two,b_Three
3,9,9.5,"15 Things",10,10.5,"30 Things"
我想要的输出是包含以下内容的新CSV:
inc,label,one,two,three
1,"a",1,1.5,"5 Things"
2,"a",5,5.5,"10 Things"
3,"a",9,9.5,"15 Things"
1,"b",2,2.5,"10 Things"
2,"b",6,6.5,"20 Things"
3,"b",10,10.5,"30 Things"
基本上:
a_One
和b_One
值应合并到同一列中)。 Inc
值(在不同位置可能会有不止一行这样的行)。 注意事项:
Inc
属性需要保留。 通常, Inc
代表不具有前缀a_
或b_
任何列。 我已经有一个正则表达式删除这些前缀。 到目前为止,我已经做到了:
> wip_path <- 'C:/path/to/horrible.csv'
> rawwip <- read.csv(wip_path, header = FALSE, fill = FALSE)
> rawwip
V1 V2 V3 V4 V5 V6 V7
1 Inc a_One a_Two a_Three b_One b_Two b_Three
2 1 1 1.5 5 Things 2 2.5 10 Things
3 2 5 5.5 10 Things 6 6.5 20 Things
4 Inc a_One a_Two a_Three b_One b_Two b_Three
5 3 9 9.5 15 Things 10 10.5 30 Things
> skips <- which(rawwip$V1==rawwip[1,1])
> skips
[1] 1 4
> filwip <- rawwip[-skips,]
> filwip
V1 V2 V3 V4 V5 V6 V7
2 1 1 1.5 5 Things 2 2.5 10 Things
3 2 5 5.5 10 Things 6 6.5 20 Things
5 3 9 9.5 15 Things 10 10.5 30 Things
> rawwip[1,]
V1 V2 V3 V4 V5 V6 V7
1 Inc a_One a_Two a_Three b_One b_Two b_Three
但是,当我尝试将tolower()应用于这些字符串时,我得到:
> tolower(rawwip[1,])
[1] "4" "4" "4" "4" "4" "4" "4"
这是非常出乎意料的。
所以我的问题是:
1)如何获取对rawwip[1,]
的标头字符串的访问权限rawwip[1,]
以便可以使用tolower()
和其他字符串操纵函数重新格式化标头字符串?
2)完成此操作后,在保留每一行的inc
值的同时,将具有共享名称的列堆叠起来的最有效方法是什么?
请记住,将有超过一千个重复的列,可以将其过滤为大约20个共享列名。 我不会提前知道每个可堆叠列的位置。 这需要在脚本中确定。
您可以使用基本的reshape()
函数。 例如输入
dd<-read.csv(text='Inc,a_One,a_Two,a_Three,b_One,b_Two,b_Three
1,1,1.5,"5 Things",2,2.5,"10 Things"
2,5,5.5,"10 Things",6,6.5,"20 Things"
inc,a_one,a_two,a_three,b_one,b_two,b_three
3,9,9.5,"15 Things",10,10.5,"30 Things"')
你可以做
dx <- reshape(subset(dd, Inc!="inc"),
varying=Map(function(x) paste(c("a","b"), x, sep="_"), c("One","Two","Three")),
v.names=c("One","Two","Three"),
idvar="Inc",
timevar="label",
times = c("a","b"),
direction="long")
dx
要得到
Inc label One Two Three
1.a 1 a 1 1.5 5 Things
2.a 2 a 5 5.5 10 Things
3.a 3 a 9 9.5 15 Things
1.b 1 b 2 2.5 10 Things
2.b 2 b 6 6.5 20 Things
3.b 3 b 10 10.5 30 Things
由于您的输入数据杂乱无章(嵌入标头),因此将所有内容创建为因素。 您可以尝试使用以下方法转换为正确的数据类型
dx[]<-lapply(lapply(dx, as.character), type.convert)
我建议的组合read.mtable
从我的GitHub上,只有“SOfun”包和merged.stack
从我的“splitstackshape”包。
这是方法。 我假设您的数据存储在工作目录中的“ somedata.txt”文件中。
我们需要的软件包:
library(splitstackshape) # for merged.stack
library(SOfun) # for read.mtable
首先,获取名称的向量。 在此过程中,将名称结构从“ a_one”更改为“ one_a”-这是merged.stack
和reshape
的一种更加方便的格式。
theNames <- gsub("(.*)_(.*)", "\\2_\\1",
tolower(scan(what = "", sep = ",",
text = readLines("somefile.txt", n = 1))))
其次,使用read.mtable
读取数据。我们通过识别所有以字母开头的行来创建数据块。 如果与您的实际数据不匹配,则可以使用更具体的正则表达式。
这将创建一个data.frame
的list
,因此我们使用do.call(rbind, ...)
将其放到单个data.frame
:
theData <- read.mtable("somefile.txt", "^[A-Za-z]", header = FALSE, sep = ",")
theData <- setNames(do.call(rbind, theData), theNames)
现在的数据如下所示:
theData
# inc one_a two_a three_a one_b two_b three_b
# Inc,a_One,a_Two,a_Three,b_One,b_Two,b_Three.1 1 1 1.5 5 Things 2 2.5 10 Things
# Inc,a_One,a_Two,a_Three,b_One,b_Two,b_Three.2 2 5 5.5 10 Things 6 6.5 20 Things
# inc,a_one,a_two,a_three,b_one,b_two,b_three 3 9 9.5 15 Things 10 10.5 30 Things
从这里,您可以使用“ splitstackshape”中的merged.stack
。
merged.stack(theData, var.stubs = c("one", "two", "three"), sep = "_")
# inc .time_1 one two three
# 1: 1 a 1 1.5 5 Things
# 2: 1 b 2 2.5 10 Things
# 3: 2 a 5 5.5 10 Things
# 4: 2 b 6 6.5 20 Things
# 5: 3 a 9 9.5 15 Things
# 6: 3 b 10 10.5 30 Things
...或从基数R reshape
:
reshape(theData, direction = "long", idvar = "inc",
varying = 2:ncol(theData), sep = "_")
# inc time one two three
# 1.a 1 a 1 1.5 5 Things
# 2.a 2 a 5 5.5 10 Things
# 3.a 3 a 9 9.5 15 Things
# 1.b 1 b 2 2.5 10 Things
# 2.b 2 b 6 6.5 20 Things
# 3.b 3 b 10 10.5 30 Things
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.