2013-04-22 4 views
1

Скажем, у меня есть CSV-файл с следующим форматом данных:Преобразования CSV данных для анализа и визуализаций

ID, Name, Gender, Q1 
1, ABC, Male, "A1;A2" 
2, ACB, Male, "A2;A3;A4" 
3, BAC, Female, "A1" 

Я хотел бы превратить его в следующий формат, чтобы мой инструмент виртуализации данных может обрабатывать его правильно:

ID, Name, Gender, Questions, Responses 
1, ABC, Male, Q1, A1 
1, ABC, Male, Q1, A2 
2, ACB, Male, Q1, A2 
2, ACB, Male, Q1, A3 
2, ACB, Male, Q1, A4 
3, BAC, Female, Q1, A1 

Использование Text to Columns функции в LibreOffice я могу легко отдельный Q1 колонка A1;A2 в разные колонки, как A1, A2, но я застрял в транспозиции и повторяя строки.

Дополнительная информация:

  • Данные собираются с помощью формы Google, к сожалению, электронные таблицы Google хранить несколько ответов выбор вопрос в одной клетке с помощью точки с запятой-разделитель, как A1;A2;A3..., в то время как мой инструмент визуализации не может видеть эту изначальную структуру данных, обрабатывать их только как одну строку, что затрудняет объединение/группировку.

  • В фактических данных (результаты опроса) У меня около 5000 записей, каждый из которых содержит несколько ячеек, требующих такой обработки, что приведет к таблице около 100 000 записей. Необходим способ автоматизации преобразования.

  • Инструмент я использую для анализа/визуализации данных «Tableau Public», у них есть Reshaper данные плагин для Excel, что полуавтомат such tasks (смотрите раздел Убедитесь, что каждая строка содержит только один элемент данных), но нет альтернативы LibreOffice.

+0

У меня такая же потребность, как и для Tableau. Я действительно удивлен, что нет стандартных инструментов для преобразования между этими двумя форматами: кросс-таблица/широкоформатная <-> normalized/long –

ответ

2

Вы можете использовать JavaScript в Google Spreadsheet для преобразования данных перед экспортом в другие приложения. Вот быстрый и грязный сценарий я просто написал для данных выборки:

function transformRows() { 
    var sheet = SpreadsheetApp.getActiveSheet(); 
    var rows = sheet.getDataRange(); 
    var numRows = rows.getNumRows(); 
    var values = rows.getValues(); 

    var newSheet = SpreadsheetApp.getActiveSpreadsheet().insertSheet("Result"); 
    var header = values[0].slice(0, values[0].length - 1); 

    header.push("Question"); 
    header.push("Answer"); 
    newSheet.appendRow(header); 

    var question = values[0][values[0].length - 1]; 

    // Note: Code below is inefficient and may exceed 6-minute timeout for sheets with 
    //  more than 1k rows. Change it to batch updating to speed up. 
    // Ref: https://developers.google.com/apps-script/reference/spreadsheet/range#setValues%28Object%29 
    for (var i = 1; i <= numRows - 1; i++) { 
    var row = values[i]; 
    var answers = row[row.length - 1].split(";"); 
    for (var ansi = 0; ansi < answers.length; ansi++) { 
     var newRow = row.slice(0, row.length - 1); 
     newRow.push(question); 
     newRow.push(answers[ansi]); 
     newSheet.appendRow(newRow); 
    } 
    } 
}; 

Чтобы использовать его:

  1. Открытый редактор сценариев в вашем открытом листе (Инструменты -> Редактор скриптов ...)
  2. Создать пустой проект для таблицы
  3. Вставьте код в редактор
  4. Сохранить и запустить его (Run -> transformRows)
  5. Retur n в таблицу, новый лист будет создан и заполнен преобразованными данными.
+0

Отличная работа, хотя я должен заметить, что сценарий приложения Google истечет через 6 минут, так как мой набор данных останавливает обработку около 4000 строк. Заменив '' '' newSheet.appendRow (...) '' 'с кешированием строк и' '' newSheet.getRange (...). SetValues ​​(...) '' ', мы можем выполнить операцию вставки (которая медленная) и избежать таймаута. [см. doc] (https://developers.google.com/apps-script/best_practices#batchOperations). – bitinn

+0

Спасибо за информацию. Раньше я не знал об этой проблеме. Добавил комментарий к моему фрагменту кода, чтобы отметить его. – SAPikachu

0

Я сделал более общую версию ответа @ SAPikachu. Он может конвертировать любое количество столбцов данных, считая, что все столбцы данных находятся справа от всех столбцов не-данных. (Не самая ясная терминология ...)

function onOpen() { 
    var ss = SpreadsheetApp.getActive(); 
    var items = [ 
    {name: 'Normalize Crosstab', functionName: 'normalizeCrosstab'}, 
    ]; 
    ss.addMenu('Normalize', items); 
} 

/* Converts crosstab format to normalized form. Given columns abcDE, the user puts the cursor somewhere in column D. 
The result is a new sheet, NormalizedResult, like this: 

a  b  c Field Value 
a1 b1 c1 D  D1 
a1 b1 c1 E  E1 
a2 b2 c2 D  D2 
a2 b2 c2 E  E2 
... 

*/ 
function normalizeCrosstab() { 
    var sheet = SpreadsheetApp.getActiveSheet(); 
    var rows = sheet.getDataRange(); 
    var numRows = rows.getNumRows(); 
    var values = rows.getValues(); 
    var firstDataCol = SpreadsheetApp.getActiveRange().getColumn(); 
    var dataCols = values[0].slice(firstDataCol-1); 

    if (Browser.msgBox("This will create a new sheet, NormalizedResult. Place your cursor is in the first data column.\\n\\n" + 
        "These will be your data columns: " + dataCols,Browser.Buttons.OK_CANCEL) == "cancel") { 
    return; 
    } 


    var resultssheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("NormalizedResult"); 
    if (resultssheet != null) { 
    SpreadsheetApp.getActive().deleteSheet(resultssheet); 
    } 
    var newSheet = SpreadsheetApp.getActiveSpreadsheet().insertSheet("NormalizedResult"); 
    var header = values[0].slice(0, firstDataCol - 1); 

    var newRows = []; 

    header.push("Field"); 
    header.push("Value"); 
    newRows.push(header); 

    for (var i = 1; i <= numRows - 1; i++) { 
    var row = values[i]; 
    for (var datacol = 0; datacol < dataCols.length; datacol ++) { 
     newRow = row.slice(0, firstDataCol - 1); // copy repeating portion of each row 
     newRow.push(values[0][firstDataCol - 1 + datacol]); // field name 
     newRow.push(values[i][firstDataCol - 1 + datacol]); // field value 
     //newSheet.appendRow(newRow); 
     newRows.push(newRow); 
    } 
    } 
    var r = newSheet.getRange(1,1,newRows.length, header.length); 
    r.setValues(newRows); 
}; 
Смежные вопросы