簡體   English   中英

PySpark 合並 dataframe 和計數值

[英]PySpark Merge dataframe and count values

我有兩個不同的數據框,我想找出df1m列和df2n列之間的交集計數。 通過交集,我的意思是兩列共有的唯一值的數量。 如果 df1 有 10 列而 df2 有 20 列,那么我將得到的交叉點數是 200。我這里只使用 PySpark。

就我而言,數據很大,我運行了以下代碼

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

但在所有這些情況下,代碼都不夠快,因為我正在運行兩個for循環。 我想創建這個字典或任何我有兩個列名和它們的交集計數的數據表示。 我嘗試使用cache但仍然不夠好。

數據集:

df1 = pd.DataFrame({'col1':['red', 'green', 'blue','black','purple'], 'col2': ['one','two','three','nine','ten'], 'col3': ['val','2','sda','452','rww']})

df2 = pd.DataFrame({'col9':['red', 'green', 'pink','orange','purple'], 'col10': ['seven','ten','nine','six','seven'], 'col11': ['val','2','dsrf','452','red']})

df1 = sqlContext.createDataFrame(df1)
df2 = sqlContext.createDataFrame(df2)

只要有列名及其計數,output 字典應該看起來像這樣或任何其他格式。 它可以是任何格式,我只關心 output。

dict = {"col1,col9":3, "col1,col10": 0, "col1,col11":1, ...... }

刪除嵌套循環並讓 Spark 為您完成它應該會顯着提高性能。 這需要兩個步驟,在此表示為函數。

第一步:收集數組中每一列的唯一值,並轉置 dataframe。

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) 僅收集唯一值並不是絕對必要的,但它可能會加快第二步。

這個 function 所做的最好用一個例子來說明:

>>> 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}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM