pyspark 在SQL中,我如何按一长串列中的每一列进行分组并获得计数,将所有列组装到一个表中?

omjgkv6w  于 2023-10-15  发布在  Spark
关注(0)|答案(3)|浏览(127)

在训练分类器之前,我对多标签数据集进行了分层样本,现在想检查它的平衡程度。数据集中的列包括:

|_Body|label_0|label_1|label_10|label_100|label_101|label_102|label_103|label_104|label_11|label_12|label_13|label_14|label_15|label_16|label_17|label_18|label_19|label_2|label_20|label_21|label_22|label_23|label_24|label_25|label_26|label_27|label_28|label_29|label_3|label_30|label_31|label_32|label_33|label_34|label_35|label_36|label_37|label_38|label_39|label_4|label_40|label_41|label_42|label_43|label_44|label_45|label_46|label_47|label_48|label_49|label_5|label_50|label_51|label_52|label_53|label_54|label_55|label_56|label_57|label_58|label_59|label_6|label_60|label_61|label_62|label_63|label_64|label_65|label_66|label_67|label_68|label_69|label_7|label_70|label_71|label_72|label_73|label_74|label_75|label_76|label_77|label_78|label_79|label_8|label_80|label_81|label_82|label_83|label_84|label_85|label_86|label_87|label_88|label_89|label_9|label_90|label_91|label_92|label_93|label_94|label_95|label_96|label_97|label_98|label_99|

我想对每个label_*列进行一次分组,并创建一个包含正/负计数结果的字典。现在我在PySpark SQL中这样完成:

# Evaluate how skewed the sample is after balancing it by resampling
stratified_sample = spark.read.json('s3://stackoverflow-events/1901/Sample.Stratified.{}.*.jsonl'.format(limit))
stratified_sample.registerTempTable('stratified_sample')

label_counts = {}
for i in range(0, 100):
  count_df = spark.sql('SELECT label_{}, COUNT(*) as total FROM stratified_sample GROUP BY label_{}'.format(i, i))
  rows = count_df.rdd.take(2)
  neg_count = getattr(rows[0], 'total')
  pos_count = getattr(rows[1], 'total')
  label_counts[i] = [neg_count, pos_count]

因此,输出为:

{0: [1034673, 14491],
 1: [1023250, 25914],
 2: [1030462, 18702],
 3: [1035645, 13519],
 4: [1037445, 11719],
 5: [1010664, 38500],
 6: [1031699, 17465],
 ...}

这感觉就像是在一个SQL语句中就可以做到的,但是我不知道如何做到这一点,也找不到现有的解决方案。显然,我不想写出所有的列名,生成SQL似乎比这个解决方案更糟糕。
SQL可以做到这一点吗?谢谢你,谢谢

5ssjco0h

5ssjco0h1#

这里是一个解决方案与单一的sql,以获得所有的pos和neg计数

sql = 'select '
for i in range(0, 100):
    sql = sql + ' sum(CASE WHEN label_{} > 0 THEN 1 ELSE 0 END) as label{}_pos_count, '.format(i,i)
    sql = sql + ' sum(CASE WHEN label_{} < 0 THEN 1 ELSE 0 END) as label{}_neg_count'.format(i,i)
    if i < 99:
        sql = sql + ', '

sql = sql + ' from stratified_sample '
df = spark.sql(sql)
rows = df.rdd.take(1)
label_counts = {}
for i in range(0, 100):
    label_counts[i] = [rows[0][2*i],rows[0][2*i+1] ]

print(label_counts)
von4xj4u

von4xj4u2#

你确实可以在一个声明中做到这一点,但我不确定表演会很好。

from pyspark.sql import functions as F
from functools import reduce

dataframes_list = [
    stratified_sample.groupBy(
        "label_{}".format(i)
    ).count().select(
        F.lit("label_{}".format(i)).alias("col"),
        "count"
    )
    for i in range(0, 100)
]

count_df = reduce(
    lambda a, b: a.union(b),
    dataframes_list
)

这将创建一个包含2列的嵌套框架,col包含您正在计数的列的名称,count包含计数的值。
为了把它变成一个dict,我让你读another post

yptwkmov

yptwkmov3#

你可以在没有group by的情况下生成sql。

SELECT COUNT(*) AS total, SUM(label_k) as positive_k ,.. FROM table

然后使用结果生成dict {k:[total-positive_k,positive_k]}

相关问题