2015-05-12 2 views
2

У меня есть CSV-файл, ужасный формат я не могу изменить (упрощенный здесь):штабелирования столбцы с одинаковыми именами в R

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,], так что я могу переформатировать их с tolower() и другими струнными манипулированиями функциями?

2) Как только я это сделал, каков наиболее эффективный способ укладки столбцов с общими именами при сохранении значения inc для каждой строки?

Имейте в виду, что будет более тысячи повторяющихся столбцов, которые могут быть отфильтрованы до, возможно, 20 разделяемых имен столбцов. Я не буду знать позицию каждого стекируемого столбца раньше времени. Это необходимо определить внутри скрипта.

ответ

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) 
+0

Возможно, моя самая большая проблема с обучением R не в состоянии найти полную документацию. Например, в моих текущих ресурсах я не могу найти документацию на Map(), которую вы использовали выше. Не могли бы вы предоставить источник документации для этой функции? Google не помог. – Shawn

+1

Внутри R просто введите '? Map', чтобы открыть документацию для этой функции. – MrFlick

+0

Awesome. Это помогает, если я знаю, что я ищу. Куда идет, если они еще не знают, что они ищут? =) Я использовал индекс [здесь] (https://stat.ethz.ch/R-manual/R-devel/library/base/html/), но ему не хватает определенных вещей, которые я нашел в другом месте. – Shawn

0

Я хотел бы предложить сочетание read.mtable от my GitHub-only "SOfun" package и 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 для чтения данных. Мы создаем куски данных, идентифицируя все строки, которые начинаются с букв. Вы можете использовать более определенное регулярное выражение, если оно не соответствует вашим фактическим данным.

Это создаст 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 с "splitstackshape" ....

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 
Смежные вопросы