【问题标题】:Python Pandas Pairwise Frequency Table with many columns具有多列的 Python Pandas 成对频率表
【发布时间】:2018-02-08 08:33:52
【问题描述】:

这里是熊猫初学者问题:

如何为所有列创建交叉频率计数表?我想使用输出来制作显示每对列之间计数的 seaborn 热图。

我有一个数据框(使用 pyspark 从 hdfs 拉下),其中包含约 70 个唯一列和大约 600K 行

样本期望输出:

    C1 C2 C3 C4 ...C70
C1  -  1  1  2
C2  1  -  0  2
C3  1  0  -  1
C4  2  2  1  -
...   
C70

样本 DF:

import numpy as np
import pandas as pd
raw_data = {'C1': [ 0, 2, 5, 0, 3], #...600K
    'C2': [3, 0 , 2, 0, 0],
    'C3': [0, 0, 0, 3, 3],
    'C4': [2, 1, 1, 4, 0]} 
df = pd.DataFrame(raw_data, columns = ['C1', 'C2', 'C3','C4'])
print(df)

我尝试过使用 pandas 的 crosstab、pivot、pivot_table 并认为解决方案正在使用交叉表,但我无法以所需的输出格式获得它(抱歉,如果我遗漏了一些明显的东西)。任何帮助表示赞赏!

【问题讨论】:

  • 你能解释一下这里的逻辑吗?为什么 c1-c4=2 和 c4-c1=1
  • 我这里的数据是提交给一个或多个实体(每列)的独立文档(行)。我希望能够确定哪对(或什至组)实体收到最多的提交。我认为热图是一种可视化的好方法(因为有很多行和列),并且从阅读 seaborn 文档的形式来看,需要这种格式的数据(我认为)。
  • 糟糕——你是对的;错字>
  • 请让您的预期输出反映发布的示例输入。你在找v = df.clip_upper(1); v.T.dot(v)吗?
  • 就是这样,谢谢!很抱歉造成混乱

标签: python pandas numpy crosstab


【解决方案1】:

clip_upper 将正值剪切到1,然后计算点积:

i = df.clip_upper(1)
j = i.T.dot(i)

j

    C1  C2  C3  C4
C1   3   1   1   2
C2   1   2   0   2
C3   1   0   2   1
C4   2   2   1   4

【讨论】:

    【解决方案2】:

    这是一个使用 spark-sql 的 PySpark DataFrame 解决方案。绝对不如@cᴏʟᴅsᴘᴇᴇᴅ 的 pandas 解决方案优雅,但也许这对于真正的大数据框很有用。

    假设您的数据位于 PySpark DataFrame spark_df 中。

    spark_df.show()
    #+---+---+---+---+
    #| C1| C2| C3| C4|
    #+---+---+---+---+
    #|  0|  3|  0|  2|
    #|  2|  0|  0|  1|
    #|  5|  2|  0|  1|
    #|  0|  0|  3|  4|
    #|  3|  0|  3|  0|
    #+---+---+---+---+
    

    创建一个空的 DataFrame 来保存输出。此模式将是一个 StringType() 列,后跟一个 IntegerType() 列,用于 spark_df 中的每一列:

    cols = spark_df.columns
    schema = StructType(
        [StructField('col', StringType())] + [StructField(c, IntegerType()) for c in cols]
    )
    output = sqlCtx.createDataFrame([], schema=schema)
    output.printSchema()
    #root
    # |-- col: string (nullable = true)
    # |-- C1: long (nullable = true)
    # |-- C2: long (nullable = true)
    # |-- C3: long (nullable = true)
    # |-- C4: long (nullable = true)
    

    将此DataFrame注册为表格:

    spark_df.registerTempTable('table')
    

    遍历 DataFrame 中的每一列并构建一个查询以获取该“行”的值。使用union() 将查询的输出添加到output

    for col in cols:
        q = "SELECT '%s' AS col," % col
        q += ",".join("SUM(CASE WHEN %s > 0 AND %s > 0 THEN 1 ELSE 0 END) AS %s " % (col, c, c) for c in cols)
        q += " FROM table t"
        output = output.union(sqlCtx.sql(q))
    

    终于输出了:

    output.show()
    #+---+---+---+---+---+
    #|col| C1| C2| C3| C4|
    #+---+---+---+---+---+
    #| C1|  3|  1|  1|  2|
    #| C2|  1|  2|  0|  2|
    #| C3|  1|  0|  2|  1|
    #| C4|  2|  2|  1|  4|
    #+---+---+---+---+---+
    

    与 pandas 版本匹配。

    【讨论】:

    • 它可能不如 pandas 优雅,但在那些庞大的数据集上会快得多;谢谢!
    • @whs2k 在 for 循环内构建整个查询可能会更好,并且在最后调用 sqlCtx.sql() 而不是在循环内调用 union()。跨度>
    猜你喜欢
    • 2016-12-07
    • 2012-07-30
    • 1970-01-01
    • 2012-06-24
    • 2019-06-14
    • 1970-01-01
    • 2019-05-07
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多