在R中堆叠具有相似名称的列

时间:2015-05-12 20:03:51

标签: 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_Oneb_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,]中的标题字符串,以便我可以使用tolower()和其他字符串操作函数重新格式化它们?

2)一旦我完成了这项工作,使用共享名称堆叠列的最有效方法是什么,同时保留每行的inc值?

请记住,将有超过一千个重复列可以过滤到大约20个共享列名。我不会提前知道每个可堆叠列的位置。这需要在脚本中确定。

2 个答案:

答案 0 :(得分:3)

您可以使用基本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)

答案 1 :(得分:0)

我建议从我的&#34; splitstackshape&#34;中read.mtable merged.stacklibrary(splitstackshape) # for merged.stack library(SOfun) # for read.mtable 的组合。封装

这是方法。我假设您的数据存储在名为&#34; somedata.txt&#34;的文件中。在你的工作目录中。

我们需要的包裹:

merged.stack

首先,抓住名字的矢量。在我们处理它时,从&#34; a_one&#34;更改名称结构。到&#34; one_a&#34; - 对于reshapetheNames <- gsub("(.*)_(.*)", "\\2_\\1", tolower(scan(what = "", sep = ",", text = readLines("somefile.txt", n = 1)))) 来说,这是一种更方便的格式。

read.mtable

其次,使用list来读取数据。我们通过识别以字母开头的所有行来创建数据块。如果它与您的实际数据不匹配,您可以使用更具体的正则表达式。

这将创建data.frame 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

这就是数据现在的样子:

merged.stack

从这里开始,您可以使用来自&#34; splitstackshape&#34; .... {/ p>的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

reshape
来自基地R的

...或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

meteor