python—计算单个列中列表中的值

yebdmbv4  于 2021-05-27  发布在  Spark
关注(0)|答案(3)|浏览(600)

我有一个pysparkDataframe,其中1列由字符串列表组成。我想计算所有行中每个字符串列表中每个元素的示例数。伪代码:

  1. counter = Counter()
  2. for attr_list in df['attr_list']:
  3. counter.update(attr_list)

另一种方法是将所有行中的所有列表连接起来,并从单个巨大的列表中构建一个计数器。在pyspark中有没有一种有效的方法可以做到这一点?
正确的输出应该是一个 collections.Counter() 对象,该对象填充了所有列中所有列表中每个项的出现次数,即,如果对于给定列,第1行具有该列表 ['a', 'b', 'c'] 第2行有一个列表 ['b', 'c', 'd'] ,我们会得到一个看起来像 {'a': 1, 'b': 2, 'c': 2, 'd': 1} .

q35jwt9p

q35jwt9p1#

如果你知道 elements 你要数数,然后你可以用这个 spark2.4+. 而且会很快 higher order function filter 以及 structs )

  1. df.show()
  2. # +------------+
  3. # | atr_list|
  4. # +------------+
  5. # |[a, b, b, c]|
  6. # | [b, c, d]|
  7. # +------------+
  8. elements=['a','b','c','d']
  9. from pyspark.sql import functions as F
  10. collected=df.withColumn("struct", F.struct(*[(F.struct(F.expr("size(filter(atr_list,x->x={}))"\
  11. .format("'"+y+"'"))).alias(y)) for y in elements]))\
  12. .select(*[F.sum(F.col("struct.{}.col1".format(x))).alias(x) for x in elements])\
  13. .collect()[0]
  14. {elements[i]: [x for x in collected][i] for i in range(len(elements))}
  15. ``` `Out: {'a': 1, 'b': 3, 'c': 2, 'd': 1}` 第二种方法,使用 `transform, aggregate, explode and groupby` (不需要指定元素):

from pyspark.sql import functions as F

a=df.withColumn("atr", F.expr("""transform(array_distinct(atr_list),x->aggregate(atr_list,0,(acc,y)->
IF(y=x, acc+1,acc)))"""))
.withColumn("zip", F.explode(F.arrays_zip(F.array_distinct("atr_list"),("atr"))))
.select("zip.*").withColumnRenamed("0","elements")
.groupBy("elements").agg(F.sum("atr").alias("sum"))
.collect()

{a[i][0]: a[i][1] for i in range(len(a))}

展开查看全部
v8wbuo2f

v8wbuo2f2#

转换为rdd的一种方法是将所有数组合并为一个数组,然后使用 Counter 上面有东西。

  1. from collections import Counter
  2. all_lists = df.select('listCol').rdd
  3. print(Counter(all_lists.map(lambda x: [i for i in x[0]]).reduce(lambda x,y: x+y)))

另一个选择是 explode 以及 groupBy 并将结果合并到 dictionary .

  1. from pyspark.sql.functions import explode
  2. explode_df = df.withColumn('exploded_list',explode(df.listCol))
  3. counts = explode_df.groupBy('exploded_list').count()
  4. counts_tuple = counts.rdd.reduce(lambda a,b : a+b)
  5. print({counts_tuple[i]:counts_tuple[i+1] for i in range(0,len(counts_tuple)-1,2)})
bpsygsoo

bpsygsoo3#

你可以试着用 distinct 以及 flatMap 方法,为此只需将列转换为和rdd并执行这些操作。

  1. counter = (df
  2. .select("attr_list")
  3. .rdd
  4. # join all strings in the list and then split to get each word
  5. .map(lambda x: " ".join(x).split(" "))
  6. .flatMap(lambda x: x)
  7. # make a tuple for each word so later it can be grouped by to get its frequency count
  8. .map(lambda x: (x, 1))
  9. .reduceByKey(lambda a,b: a+b)
  10. .collectAsMap())

相关问题