我有两个不同的数据框,我想找出glueContext.sparkContext.hadoopConfiguration.set("fs.s3.canned.acl", "BucketOwnerFullControl")
的{{1}}列和m
的{{1}}列之间的交点数。通过交集,我的意思是两个列共有的唯一值的数量。如果df1有10列,而df2有20列,那么我得到的交集数将是200。在这里我仅使用PySpark。
对于我来说,数据量很大,我运行了以下代码
df1
或此代码
n
或者这个
df2
但是在所有这些情况下,由于我正在运行两个dict = {}
for a in df1.columns:
i_u = df1.select(a).distinct()
i_u = i_u.select(a).collect()
for b in df2.columns:
i_b = df2.select(b).distinct()
i_b = i_b.select(b).collect()
l = len(list(set(i_u) & set(i_b)))
str = a + ","+b+","
dict[str] = l
循环,因此代码不够快。我要创建此字典或任何具有两个列名及其交点数的数据表示形式。我尝试使用dict = {}
for a in df1.columns:
if not "." in a:
for b in df2.columns:
l = df1.join(df2, df1[a] == df2[b], how="inner")
l = l.select(a).distinct().count()
str = a + ","+b+","
dict[str] = l
,但仍然不够好。
数据集:
dict = {}
for a in df1.columns:
i_u = df1.select(a).distinct()
for b in df2.columns:
a_u = df2.select(b).distinct()
l = i_u.join(a_u, i_u[a] == a_u[b], how="inner").count()
str = a + ","+b+","
dict[str] = l
只要有列名及其计数,输出字典应看起来像这样或其他任何格式。它可以是任何格式,我只关心输出。
dict = {“ col1,col9”:3,“ col1,col10”:0,“ col1,col11”:1,......
答案 0 :(得分:2)
删除嵌套循环并让Spark为您完成应该大大提高性能。这需要两个步骤,在这里表示为函数。
第一步:在数组的每一列中收集唯一值并转置数据框。
from pyspark.sql import functions as F
def unique_and_transpose(df):
df = df.select([F.collect_set(col).alias(col) for col in df.columns])
params = []
for col in df.columns:
params.extend([F.lit(col), col])
return df.select(F.explode(F.create_map(*params)).alias('column', 'values'))
如果保证所有列都没有重复值,则可以将F.collect_set(col)
替换为F.collect_array(col)
。严格来说,仅收集唯一值不是必需的,但可以加快第二步的速度。
此功能的作用最好通过一个示例来说明:
>>> df1.show()
+------+-----+----+
| col1| col2|col3|
+------+-----+----+
| red| one| val|
| green| two| 2|
| blue|three| sda|
| black| nine| 452|
|purple| ten| rww|
+------+-----+----+
>>> unique_and_transpose(df1).show(3, False)
+------+---------------------------------+
|column|values |
+------+---------------------------------+
|col3 |[sda, 452, rww, 2, val] |
|col1 |[blue, green, red, black, purple]|
|col2 |[nine, one, three, two, ten] |
+------+---------------------------------+
第二步::创建转置数据集的笛卡尔积并导出您要寻找的数量。
def cross_relate(df1, df2):
return df1.alias('df1').crossJoin(df2.alias('df2')).select(
F.col('df1.column').alias('col_1'),
F.col('df2.column').alias('col_2'),
F.size(F.array_intersect('df1.values', 'df2.values')).alias('nvals')
)
笛卡尔乘积可以执行两个嵌套循环的操作,但是它只能按行工作,因此需要首先转置数据集。
借助这两个函数,您可以像这样计算每对列的唯一公共值的数量:
df1_ut = unique_and_transpose(df1).cache()
df2_ut = unique_and_transpose(df2).cache()
df = cross_relate(df1_ut, df2_ut)
结果是:
>>> df.show()
+-----+-----+-----+
|col_1|col_2|nvals|
+-----+-----+-----+
| col3|col10| 0|
| col3| col9| 0|
| col3|col11| 3|
| col1|col10| 0|
| col1| col9| 3|
| col1|col11| 1|
| col2|col10| 2|
| col2| col9| 0|
| col2|col11| 0|
+-----+-----+-----+
您想要一本字典,这又是一个步骤:
res = {f"{row.col_1},{row.col_2}": row.nvals for row in df.collect()}
>>> from pprint import pprint
>>> pprint(res)
{'col1,col10': 0,
'col1,col11': 1,
'col1,col9': 3,
'col2,col10': 2,
'col2,col11': 0,
'col2,col9': 0,
'col3,col10': 0,
'col3,col11': 3,
'col3,col9': 0}