【问题标题】:Normalize (reformat) cross-tab data for Tableau without using Excel在不使用 Excel 的情况下为 Tableau 规范化(重新格式化)交叉表数据
【发布时间】:2015-03-04 16:30:46
【问题描述】:

Tableau 通常在 input data is in "normalized" format 时效果最好,而不是交叉表。这也称为从“宽格式”转换为“长格式”。

即转换自:

收件人:

Tableau 提供了"reshaping tool" for Excel users,但如果您没有 Excel,就会卡住。

那么如何在不使用 Excel 的情况下将电子表格转换为这种格式?

【问题讨论】:

    标签: google-sheets normalization reshape tableau-api data-manipulation


    【解决方案1】:

    较新版本的 Tableau(9.0 及更高版本)允许在导入时重新调整数据。就像选择要堆叠的列一样简单。 Here's a useful tutorial.

    2018 年,Tableau 发布了 Tableau Prep Builder,用于重塑和整理数据以供分析。

    其他一些可用于重塑和清理数据的商业工具值得研究:

    Trifacta 是由参与之前学术DataWrangler 项目的一些人创建的。有人告诉我,Alteryx 非常适合地理空间相关数据的一些准备任务,并且遇到了一些热情的 Paxata 用户。

    我对他们的实际操作经验太少,只能参考他们的网站,目前倾向于使用 Python 脚本。

    如果您想将要合并的列“折叠”成一列。 Tableau 写了一个有用的tutorial here。 Tableau 9 引入了一些有用的重塑功能,用于取消透视表和拆分列。

    【讨论】:

    • 嗯,谢谢。我用谷歌搜索了很长时间,但从未找到。太糟糕了,该软件不再开发。
    • 仅供参考,Steve 的评论指的是 DataWrangler 项目,该项目已被上面的 COTS 包 Trifecta 及其竞争对手所取代
    【解决方案2】:

    如果您对命令行和使用管道组合小工具的 Unix 风格感到满意,请查看开源 csvkit 工具套件。

    您可以通过多种方式组合这些实用程序以获得不同的效果,因此确切的步骤顺序取决于您的数据集(毕竟这是工具的重点)。

    但是对于重塑任务,您可以使用 csvcut 提取感兴趣的列,csvgrep 提取感兴趣的行,使用 cvsstack将多个 csv 文件合并为一个较长的文件,并使用 -g 和 -n 选项添加分组字段。

    还有其他几个有用的命令,如果你熟悉 Unix 或 linux,你可以从命令名称中快速了解它们的作用。

    【讨论】:

    • 很高兴知道,但我不认为“检查这个工具”真的有资格作为答案。 CSVKit 是否专门解决了这个问题?如果是这样,怎么做?工具步骤的顺序是什么?
    • 我编辑了答案,至少部分指出了如何使用 csvkit 来重塑任务。文档也非常清晰简洁。
    • 我仍然没有看到这种命令组合如何解决问题。 csvstack 组合了多个文件(我没有),-g 标志只是添加了一个额外的列,每个文件都有一个值。您是否建议将带有 csvcut/csvgrep 的文件拆分为每个字段/值组合的一个文件,然后使用 csvstack 重新加入它们?
    • 如果您只有几个小组可以合作,这是解决问题的一种方法。或者构建一个脚本来执行此操作并隐藏临时文件。或者,使用 csvpy3 将其加载到 python3 并根据需要交互地重塑。并不是说它是所有重塑问题的答案,但 Unix 管道/小工具方法让您可以灵活地用很少的代码逐步解决各种各样的问题。
    • 是的,csvkit 工具绝对不错 - 即使只是从大文件中选择几列的能力有时也非常方便。
    【解决方案3】:

    嗯,你可以用我做的这个方便的Google Sheets script

    /*
    normalizeCrossTab: 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
    ...
    
    Author: 
    Steve Bennett
    stevage@gmail.com
    @stevage1
    
    Licence: Public Domain
    
    */
    
    function start() {
      var html = HtmlService.createHtmlOutput(
        '<style>ol { padding-left: 1.5em; }</style>' + 
        '<script src="//code.jquery.com/jquery-1.11.2.min.js"></script>' +
        '<script>' + 
        'function allDone(msg) { ' +
        '  $("#normalizeBtn").hide();' +
        '  $("#datacols-output").html("<p>Your normalized data is in a sheet called NormalizedResult. If you run the normalization again, that sheet will be deleted and replaced.</p>");' +
        '};' +
        'function gotCols(cols) { ' + 
        '  $("#datacols-output").html(\'<p>These will be your dependent variables:</p><ul id="datacols"></ul>\'); ' + 
        '  $("#normalizeBtn").show();' +
        '  $.each(cols, function() {' + 
        '    $("#datacols").append($("<li>").text(this)); ' + 
        '  });' + 
        '  $("#datacols").after("<p>If they don\'t look right, move the cursor and press <i>Continue</i>.</p>"); ' + 
        '}' + 
        '</script>' + 
        '<link rel="stylesheet" href="https://ssl.gstatic.com/docs/script/css/add-ons.css">' +
        '<h2>Convert cross-tab</h2>'+
        '<p>This macro converts <i>cross-tab</i> data which has multiple dependent variables (eg, observations, sales figures) per row into a <i>normalized</i> format with one dependent variable per row.</p>' + 
        '<p>The name of each dependent variable becomes the value of a new column called <code>Field</code> and its value goes in a column called <code>Value</code>.</p>' +
        '<ol><li>Move <b>all independent variable columns to the left</b></li>' + 
        '    <li>Place the <b>cursor in the first dependent variable column</li></ol>'+
        '<p><button onClick="google.script.run.withSuccessHandler(gotCols).getDataColumns();">Continue</button></p>' + 
        '<p id="datacols-output"></p>' +
        '<p><button id="normalizeBtn" class="create" style="display:none;" onClick="google.script.run.withSuccessHandler(allDone).normalizeCrosstab(true);">Normalize</button></p>' + 
      '<br/><p><a target="_blank" href="http://kb.tableausoftware.com/articles/knowledgebase/denormalize-data">More information</a></p>')
          .setSandboxMode(HtmlService.SandboxMode.IFRAME)
          .setTitle('Normalize cross-tab')
          .setWidth(300);
      SpreadsheetApp.getUi() // Or DocumentApp or FormApp.
          .showSidebar(html);
    }
    
    function onOpen() {
      var ss = SpreadsheetApp.getActive();
      var items = [
        {name: 'Normalize Crosstab', functionName: 'start'},
      ];
      ss.addMenu('Normalize', items);
    }
    
    
    function normalizeCrosstab(really) {
      if (!really) {
        return start();
      }
      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);
    
      var resultssheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("NormalizedResult");
      if (resultssheet != null) {
        SpreadsheetApp.getActive().deleteSheet(resultssheet);
      }
      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
          newRows.push(newRow);
        }
      }
      var newSheet = SpreadsheetApp.getActiveSpreadsheet().insertSheet("NormalizedResult");
      var r = newSheet.getRange(1,1,newRows.length, header.length);
      r.setValues(newRows);
    };
    
    function getDataColumns() {  
      var sheet = SpreadsheetApp.getActiveSheet(); 
      var rows = sheet.getDataRange();
      var values = rows.getValues();
      var firstDataCol = SpreadsheetApp.getActiveRange().getColumn();
      var dataCols = values[0].slice(firstDataCol-1);
      return dataCols;
    
    }
    

    Full write-up with instructions on how to install.

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-09-07
      • 2018-11-16
      • 2010-09-15
      • 2020-02-23
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多