【问题标题】:Convert columns to rows in Spark SQL在 Spark SQL 中将列转换为行
【发布时间】:2022-01-05 22:44:46
【问题描述】:

我有一些这样的数据:

ID Value1 Value2 Value40
101 3 520 2001
102 29 530 2020

我想获取这些数据并将其转换为 KV 样式对

ID ValueVv ValueDesc
101 3 Value1
101 520 Value2
101 2001 Value40

我认为这是一个支点,但我想不出这在代码中应该是什么样子。

我正在尝试在 PySQL 中解决,但也在 Python DataFrame 中解决,因为我正在使用 Spark。

我可以很容易地使用 SQL 将每一列合并到一个输出中,但我希望有一种更有效的方法?

我已将 melt 视为一个选项和 stack。但我不确定如何有效地做到这一点。

【问题讨论】:

    标签: sql apache-spark pivot transform union


    【解决方案1】:

    它与 pivot 正好相反 - 它被称为 unpivot
    在 Spark 中,反透视是使用 stack 函数实现的。

    使用 PySpark,如果您没有很多列,您可以这样做:

    from pyspark.sql import SparkSession, functions as F
    spark = SparkSession.builder.getOrCreate()
    df = spark.createDataFrame(
        [(101, 3, 520, 2001),
         (102, 29, 530, 2020)],
        ['ID', 'Value1', 'Value2', 'Value40'])
    
    df = df.select(
        "ID",
        F.expr("stack(3, Value1, 'Value1', Value2, 'Value2', Value40, 'Value40') as (ValueVv, ValueDesc)")
    )
    

    从您的示例中,我看到您可能有很多列。在这种情况下,您可以使用如下内容:

    cols_to_unpivot = [f"{c}, \'{c}\'" for c in df.columns if c != 'ID']
    stack_string = ", ".join(cols_to_unpivot)
    df = df.select(
        "ID",
        F.expr(f"stack({len(cols_to_unpivot)}, {stack_string}) as (ValueVv, ValueDesc)")
    )
    

    对于示例数据,两个版本都返回

    +---+-------+---------+
    | ID|ValueVv|ValueDesc|
    +---+-------+---------+
    |101|      3|   Value1|
    |101|    520|   Value2|
    |101|   2001|  Value40|
    |102|     29|   Value1|
    |102|    530|   Value2|
    |102|   2020|  Value40|
    +---+-------+---------+
    

    【讨论】:

    • 谢谢你,我会试试看的!
    • 这行得通! ,我无法让可变数量的列工作,因为在我的实际数据中我似乎有一些数据类型转换错误。我猜测我需要调试的问题的流程..
    • 我刚刚发现是因为第一列会推断出后续列将被堆叠成什么......在我的情况下,你不能将字符串填充到整数字段中......跨度>
    【解决方案2】:

    到目前为止,我已经完成了这项工作,但希望不使用 pandas 来实现这一点.. 而是仅使用 spark 数据框。

    import pandas as pd
        
    def main():
        
        data={'AnID':[2001,2002,2003,2004],
              'Name':['adam','jane','Sarah','Ryan'], 
              'Age':[23,22,21,24], 
              'Age1':[24,52,51,264], 
              'Age2':[263,262,261,264]}
    
        df=pd.DataFrame(data)
    
       #Iterate the DataFrame so that we can pivot the "columns" into Rows
        schema = df.columns  #gives me the names of the columns
           
        df.index[0]
        
        #loop Through the id to pivot on (assume it's the first one in the df)
        
        j = 0
        df2=pd.DataFrame()
        while j < schema.size:
            curvalid = schema[j]
            idname = schema[j] #get each element of the array
            vval = df[idname].values  #Grab all the values for the given "column"
     
        #then get the data for that array element and populate a new object
        
            
    
            i = 0
            while i < vval.size:
                df3=pd.DataFrame({'DemoDesc' : curvalid, 'DemoID' : vval[i]}, index=[i])
                df2 = df2.append(df3,ignore_index=True)
                i = i + 1;
            j = j + 1;
        print(df2) #print the dataframe
        return;
        
    main()
    

    【讨论】:

    • 这是 python 代码,我的格式化在 SE 中很糟糕 :)
    【解决方案3】:

    你可以使用flatmap如下:

    val schema = df.schema
    val df2 = df.flatMap(row => {
        val id = row.getString(0)
        (1 until row.size).map(i => {
            (id, schema(i).name, row.getString(i))
        })
    }).toDF("ID", "ValueVv", "ValueDesc")
    
    df2.show()
    +---+-------+---------+
    | ID|ValueVv|ValueDesc|
    +---+-------+---------+
    |101| Value1|        3|
    |101| Value2|      520|
    |101|Value40|     2001|
    |102| Value1|       29|
    |102| Value2|      530|
    |102|Value40|     2020|
    +---+-------+---------+
    

    或来自此linkstack 函数。

    【讨论】:

    • 谢谢,我会尝试在我的代码中使用它。我也会再看看堆栈
    • 这对我没有直接作用,而是我在下面做了以下回答
    猜你喜欢
    • 2015-12-05
    • 2015-09-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-09-25
    相关资源
    最近更新 更多