使用.allias

时间:2019-05-15 19:58:19

标签: apache-spark dataframe apache-spark-sql pyspark-sql

我是使用spark-sql刚接触spark(2.x.x)的人,我使用spark sql上下文创建了一个数据框。

dff = sqlCtx.read.format("com.databricks.spark.csv").option("header", "true").option("inferSchema","true").option("delimiter","\t").load("/home/hduser/Desktop/allFromDesktop/pyspark/creditData.csv")

dff.show()

Income|Limit|Rating|Cards|Age|Education|Gender|Student|Married|       Ethnicity|Balance|Age_class|
+---+------------------+-----+------+-----+---+---------+------+-------+-------+----------------+-------+---------+
|  0|14.890999999999998| 3606|   283|    2| 34|       11|  Male|     No|    Yes|       Caucasian|    333|    25-34|
|  1|           106.025| 6645|   483|    3| 82|       15|Female|    Yes|    Yes|           Asian|    903|      65+|
|  2|104.59299999999999| 7075|   514|    4| 71|       11|  Male|     No|     No|           Asian|    580|      65+|

我尝试对代码进行单元测试

tab=dff.select(['Age_class','Balance','Limit']).groupby('Age_class').agg
  (F.count('Limit')  ,F.mean('Limit').alias('Limit_avg'),F.min('Limit').alias('Limit_min'),F.max('Limit').alias('Limit_max')).withColumn('total',sum(col('Limit')).
  over(Window)).withColumn('Percent',col('Limit')*100/col('total')).drop(c
  ol('total'))
  tab.show()

并发现,一旦agg(),count函数执行原始列,就会被新的.allias列名替换 单元测试#1(成功执行python代码的第一部分)

tab=dff.select(['Age_class','Balance','Limit']).groupby('Age_class').agg(F.count('Limit_count')
    ,F.mean('Limit').alias('Limit_avg'),
    F.min('Limit').alias('Limit_min'),
    F.max('Limit').alias('Limit_max'))
    tab.show()

输出:

output:
---------+------------+------------------+---------+---------+
|Age_class|count(Limit)|         Limit_avg|Limit_min|Limit_max|
+---------+------------+------------------+---------+---------+
|    45-54|          65| 4836.630769230769|      855|    11200|
|      <25|          11|3932.6363636363635|     2120|     6375|
|    55-64|          68|            4530.0|     1311|    11966|
##Here you can see i lost my original 'Limit' column ##

具有“限制”列的原始数据框已被删除(为什么?)被新列替换,即当代码的第二部分运行时我松开了原始数据框列,无法找到原始数据框数据框中的列。 o .. 语句的其余部分,即* .withColumn('total',sum(col('Limit'))。    over(Window))。withColumn('Percent',col('Limit') 100 / col('total'))。drop(col('total'))

显示错误:

Py4JJavaError: An error occurred while calling o2104.withColumn.
: org.apache.spark.sql.AnalysisException: cannot resolve '`Limit`' given input columns: [Age_class, Limit_max, Limit_min, Limit_avg, count(Limit)];;

现在,当我将groupby子句更改为->>。groupby('Age_class','Limit')插入的.groupby('Age_class')时,我的代码将以所需的结果执行** 问题1:为什么我需要在groupby()子句中添加“限制”列?当我在SELECT语句中提到它时 问题2:执行后,即使iam使用“ groupby”,“ Age_class”列也不会转换为groups(bins),请参见下面的预期结果表,我期望的是??

+---------+----------+------------------+----------+----------+-------+
|age_class|Limit|count(Limit)|Limit_avg|Limit_min|Limit_max|Percentage
+---------+----------+------------------+----------+----------+-------+
|
  45-54     |120|3183.0666666666666|338|12612|12.0||
  <25       |150| 2970.733333333333|276|15672|15.0||
  55-64     |56| 3493.660714285714|385|15945|5.6||
  35-44     |254| 3403.771653543307|250|15857|25.4||
  25-34     |397| 3298.823677581864|343|18424|39.7||
  65+       |23|3210.1739130434785|571|14896|2.3|
+---------+----------+------------------+----------+----------+-------+
tab=dff.select(['Age_class','Balance','Limit']).groupby('Age_class','Limit').agg(F.count('Limit')
,F.mean('Limit').alias('Limit_avg'),
F.min('Limit').alias('Limit_min'),
F.max('Limit').alias('Limit_max')).withColumn('total',sum(col('Limit')).over(Window)).withColumn('Percent',col('Limit')*100/col('total')).drop(col('total'))
tab.show()

实际输出(“ Age_class”未转换为组(也称为垃圾箱)):

+---------+-----+------------+---------+---------+---------+-------------------+
|Age_class|Limit|count(Limit)|Limit_avg|Limit_min|Limit_max|            Percent|
+---------+-----+------------+---------+---------+---------+-------------------+
|    45-54| 7838|           1|   7838.0|     7838|     7838| 0.4137807247233719|
|    35-44|  886|           1|    886.0|      886|      886|0.04677337612974069|
|    45-54| 4632|           1|   4632.0|     4632|     4632|  0.244530788073317|
|    55-64| 1448|           1|   1448.0|     1448|     1448|0.07644226708336853|
|    55-64| 5107|           1|   5107.0|     5107|     5107| 0.2696068080074331|
|    45-54| 2586|           1|   2586.0|     2586|     2586| 0.1365191316834192|
|    35-44| 4159|           1|   4159.0|     4159|     4159| 0.2195603513810288|
|    45-54| 4943|           1|   4943.0|     4943|     4943| 0.2609489821775488|
|    45-54| 2558|           1|   2558.0|     2558|     2558|0.13504096629782922|
|    25-34| 3969|           1|   3969.0|     3969|     3969|0.20952994340738237|
|    35-44| 5319|           1|   5319.0|     5319|     5319| 0.2807986316411859|
|    45-54| 8100|           1|   8100.0|     8100|     8100| 0.4276121294028212|
|    45-54| 6040|           1|   6040.0|     6040|     6040| 0.3188613903201284|
|    45-54| 4673|           1|   4673.0|     4673|     4673|0.24669524453078806|
|      65+| 2330|           1|   2330.0|     2330|     2330| 0.1230044767294535|
|    45-54| 6922|           1|   6922.0|     6922|     6922| 0.3654235999662134|
|      65+| 4263|           1|   4263.0|     4263|     4263|0.22505067995607736|
|    25-34| 4391|           1|   4391.0|     4391|     4391|0.23180800743306024|
|      65+| 7499|           1|   7499.0|     7499|     7499|0.39588436523355014|
|    45-54| 8732|           1|   8732.0|     8732|     8732|  0.460976433820424|
+---------+-----+------------+---------+---------+---------+-------------------+

1 个答案:

答案 0 :(得分:1)

就像@pault所说,因为您仅按Age_class分组。如果使用聚集函数,则结果数据框将仅返回聚集的列(即,您尝试聚集的目标:count(Limit) Limit_avg Limit_min Limit_max())和维列对其应用聚合函数(即Age_class)。

如果要保留'Limit',则至少应对其应用一些聚合函数,例如:

tab=dff.select(['Age_class','Balance','Limit']) \
.groupby('Limit', 'Age_class') \
.agg(F.count('Limit_count'),
     F.mean('Limit').alias('Limit_avg'),
     F.min('Limit').alias('Limit_min'),
     F.max('Limit').alias('Limit_max'))

至于为什么要在'Limit'中加入groupby(),通常来说,您将编写类似:

df.select(col1, col2, col3, col4) \
.groupBy(col1, col3) \
.aggregate(F.count(col1), F.sum(col3))

您可以这样想:

对于给定的PySpark DataFrame df,我们选择其列col1 ... col4的一部分来获得较小的DataFrame df.select(col1, col2, col3, col4)

对于这个较小的DataFrame,我们想针对某些维度检查一些汇总结果:我们想知道我们关心的维度,即col1col3,该维度有多少行col1(即F.count(col1))和维度col3(即F.sum(col3)的总和是多少。

我关心的是那些尺寸?它们在.groupBy(col1, col3)中定义。