如何使用行的值作为新列重新格式化数据集?

Posted

技术标签:

【中文标题】如何使用行的值作为新列重新格式化数据集?【英文标题】:How to reformat a dataset using the values of rows as new columns? 【发布时间】:2015-03-14 21:57:43 【问题描述】:

我有一个如下所示的数据集:

id | test_id
---+--------
1  | a
1  | b
1  | u 
2  | a 
2  | u 
3  | a 
3  | b 
3  | u

并且我想将它汇总到一个新表中,这样test_id 是列名(以及 id),并且行是 1 或 0,具体取决于是否对该 id 进行了测试,像这样

id | a | b | u
---+---+---+--
1  | 1 | 1 | 1
2  | 1 | 0 | 1
3  | 1 | 1 | 1

Postgres 中有没有一种方法可以像这样重新排列表格?

【问题讨论】:

test_id 中不同项目的数量是固定的还是还有其他项目? test_id 项目已修复。实际上有大约30个测试项目。但是每个id可能没有30个关联test_ids 如果一个 id 没有关联的 test_id 他们会在我的答案中得到 0。 是的。谢谢你,效果很好。有没有办法计算它们?事实证明,对于给定的客户,一些 test_ids 重复。这意味着客户已经对特定的test_id 进行了两次测试。如果为零,则加一。如果一个,再添加一个(2),等等。 如果您想计算客户参加每个测试的次数,只需将max() 更改为sum()。这将为未参加考试的人分配 0 和 N(参加考试的次数)。请参阅此示例:sqlfiddle.com/#!15/59c3f/1 【参考方案1】:

如果可能的test_id 的数量是固定的并且已知,那么最简单的方法是使用这样的条件表达式:

select 
    id, 
    max(case when test_id = 'a' then 1 else 0 end) as a,
    max(case when test_id = 'b' then 1 else 0 end) as b,
    max(case when test_id = 'u' then 1 else 0 end) as u
from your_table
group by id
order by id

Sample SQL Fiddle

如果test_id 的值未知并且可以变化,那么您需要使用动态 sql 来生成查询。

【讨论】:

【参考方案2】:

给定一组test_id 的实际交叉表(“pivot”)解决方案:

SELECT id
     , COALESCE(a, 0) AS a
     , COALESCE(b, 0) AS b
     , COALESCE(u, 0) AS u
FROM   crosstab('SELECT id, test_id, 1 AS val FROM tbl ORDER BY 1,2'
              , $$VALUES ('a'), ('b'), ('u')$$
       ) AS t (id int, a int, b int, u int);

对于test_id 的动态集,您需要在第一个查询中构建语句并在第二个查询中执行它。或者你返回数组。

与此类似:

PostgreSQL 9.3: Dynamic pivot table

crosstab() 的基本知识(阅读本文,如果您不熟悉它!):

PostgreSQL Crosstab Query

替代方案:

Conditional SQL count

【讨论】:

这看起来可行,但唯一需要注意的是我不能在我正在使用的数据库上使用 crosstab()。 @aubonphysics:考虑我在第 9.4 节中没有crosstab() 的更短或新语法的最后一个链接。 我会看一下然后回复你。谢谢。

以上是关于如何使用行的值作为新列重新格式化数据集?的主要内容,如果未能解决你的问题,请参考以下文章

添加一个新列,其中包含满足条件的所有行的值列表

如何将具有值的列添加到 Spark Java 中的新数据集?

如何将具有值的新列添加到现有数据表?

如何使用实际数据帧中两列中的值索引另一个数据帧,从而在实际数据框中创建列

如何在 Scala Spark 中使用具有许多条件的“.withColumn”为数据集创建新列

在不包括当前行的两列之间使用pandas groupby除法创建一个新列