分组数据的模式(pySpark
Mode of grouped data in (py)Spark
我有一个包含多列的 spark DataFrame。我想根据一列对行进行分组,然后为每组找到第二列的模式。使用 pandas DataFrame,我会做这样的事情:
rand_values = np.random.randint(max_value,
size=num_values).reshape((num_values/2, 2))
rand_values = pd.DataFrame(rand_values, columns=['x', 'y'])
rand_values['x'] = rand_values['x'] > max_value/2
rand_values['x'] = rand_values['x'].astype('int32')
print(rand_values)
## x y
## 0 0 0
## 1 0 4
## 2 0 1
## 3 1 1
## 4 1 2
def mode(series):
return scipy.stats.mode(series['y'])[0][0]
rand_values.groupby('x').apply(mode)
## x
## 0 4
## 1 1
## dtype: int64
在 pyspark 中,我能够找到单列的模式
df = sql_context.createDataFrame(rand_values)
def mode_spark(df, column):
# Group by column and count the number of occurrences
# of each x value
counts = df.groupBy(column).count()
# - Find the maximum value in the 'counts' column
# - Join with the counts dataframe to select the row
# with the maximum count
# - Select the first element of this dataframe and
# take the value in column
mode = counts.join(
counts.agg(F.max('count').alias('count')),
on='count'
).limit(1).select(column)
return mode.first()[column]
mode_spark(df, 'x')
## 1
mode_spark(df, 'y')
## 1
我不知道如何将该函数应用于分组数据。如果无法将此逻辑直接应用于 DataFrame,是否可以通过其他方式实现相同的效果?
提前致谢!
zero323 推荐的解决方案。
原解:
首先,计算每个 (x, y) 组合出现的次数。
counts = df.groupBy(['x', 'y']).count().alias('counts')
counts.show()
## +---+---+-----+
## | x| y|count|
## +---+---+-----+
## | 0| 1| 2|
## | 0| 3| 2|
## | 0| 4| 2|
## | 1| 1| 3|
## | 1| 3| 1|
## +---+---+-----+
解决方案 1:按 'x' 分组,通过取每个组中计数的最大值进行聚合。最后,删除 'count' 列。
result = (counts
.groupBy('x')
.agg(F.max(F.struct(F.col('count'),
F.col('y'))).alias('max'))
.select(F.col('x'), F.col('max.y'))
)
result.show()
## +---+---+
## | x| y|
## +---+---+
## | 0| 4|
## | 1| 1|
## +---+---+
解决方案 2:使用 window,按 'x' 分区,按 'count' 列排序。现在,选择每个分区中的第一行。
win = Window().partitionBy('x').orderBy(F.col('count').desc())
result = (counts
.withColumn('row_num', F.rowNumber().over(win))
.where(F.col('row_num') == 1)
.select('x', 'y')
)
result.show()
## +---+---+
## | x| y|
## +---+---+
## | 0| 1|
## | 1| 1|
## +---+---+
由于行的排序方式不同,这两个结果有不同的结果。如果没有关系,这两种方法给出相同的结果。
我有一个包含多列的 spark DataFrame。我想根据一列对行进行分组,然后为每组找到第二列的模式。使用 pandas DataFrame,我会做这样的事情:
rand_values = np.random.randint(max_value,
size=num_values).reshape((num_values/2, 2))
rand_values = pd.DataFrame(rand_values, columns=['x', 'y'])
rand_values['x'] = rand_values['x'] > max_value/2
rand_values['x'] = rand_values['x'].astype('int32')
print(rand_values)
## x y
## 0 0 0
## 1 0 4
## 2 0 1
## 3 1 1
## 4 1 2
def mode(series):
return scipy.stats.mode(series['y'])[0][0]
rand_values.groupby('x').apply(mode)
## x
## 0 4
## 1 1
## dtype: int64
在 pyspark 中,我能够找到单列的模式
df = sql_context.createDataFrame(rand_values)
def mode_spark(df, column):
# Group by column and count the number of occurrences
# of each x value
counts = df.groupBy(column).count()
# - Find the maximum value in the 'counts' column
# - Join with the counts dataframe to select the row
# with the maximum count
# - Select the first element of this dataframe and
# take the value in column
mode = counts.join(
counts.agg(F.max('count').alias('count')),
on='count'
).limit(1).select(column)
return mode.first()[column]
mode_spark(df, 'x')
## 1
mode_spark(df, 'y')
## 1
我不知道如何将该函数应用于分组数据。如果无法将此逻辑直接应用于 DataFrame,是否可以通过其他方式实现相同的效果?
提前致谢!
zero323 推荐的解决方案。
原解:
首先,计算每个 (x, y) 组合出现的次数。
counts = df.groupBy(['x', 'y']).count().alias('counts')
counts.show()
## +---+---+-----+
## | x| y|count|
## +---+---+-----+
## | 0| 1| 2|
## | 0| 3| 2|
## | 0| 4| 2|
## | 1| 1| 3|
## | 1| 3| 1|
## +---+---+-----+
解决方案 1:按 'x' 分组,通过取每个组中计数的最大值进行聚合。最后,删除 'count' 列。
result = (counts
.groupBy('x')
.agg(F.max(F.struct(F.col('count'),
F.col('y'))).alias('max'))
.select(F.col('x'), F.col('max.y'))
)
result.show()
## +---+---+
## | x| y|
## +---+---+
## | 0| 4|
## | 1| 1|
## +---+---+
解决方案 2:使用 window,按 'x' 分区,按 'count' 列排序。现在,选择每个分区中的第一行。
win = Window().partitionBy('x').orderBy(F.col('count').desc())
result = (counts
.withColumn('row_num', F.rowNumber().over(win))
.where(F.col('row_num') == 1)
.select('x', 'y')
)
result.show()
## +---+---+
## | x| y|
## +---+---+
## | 0| 1|
## | 1| 1|
## +---+---+
由于行的排序方式不同,这两个结果有不同的结果。如果没有关系,这两种方法给出相同的结果。