一些模擬資料:
pd.DataFrame({'date': {0: Timestamp('2021-08-01 '),
1: Timestamp('2022-08-01 '),
2: Timestamp('2021-08-02 '),
3: Timestamp('2021-08-01 '),
4: Timestamp('2022-08-01 '),
5: Timestamp('2022-08-01 '),
6: Timestamp('2022-08-01 ') },
'product_nr': {0: 1, 1: 2, 2: 3, 3: 4, 4: 5, 5: 6, 6: 7},
'Category': {0: 'Cars', 1: 'Cars', 2: 'Cats', 3: 'Dogs', 4: 'Dogs', 5: 'Cats', 6 :'Cats'},
'price': {0: '34',
1: '24',
2: '244',
3: '284',
4: '274',
5: '354',
6 : '250'}} )
如何在具有特定條件的同一資料幀上進行內部聯接?我想比較同一類別的行之間的價格。期望的輸出:
pd.DataFrame({
'product_nr': {0: 1, 1: 3, 2: 5, 3: 7, 4:7},
'Category': {0: 'Cars', 1: 'Cats', 2: 'Dogs', 3:'Cats', 4:'Cats'},
'price': {0: '34',
1: '244',
2: '274',
3: '250',
4: '250'},
'product_to_be_compared' : {0: 2, 1: 6, 2: 4, 3:3 , 4:6}
} )
即,我想做一個內部連接/交叉連接(不確定什么最合適)。我有一個大資料框,如果它們是相同的類別和日期,我想將它們配對在一起。理想情況下,我更愿意洗掉重復的對,這意味著我想要的輸出是 4 行。
uj5u.com熱心網友回復:
根據您的問題,我知道您熟悉 PySpark。這就是使用 PySpark 資料幀的方法。即使它使用外部itertools庫,它也應該表現良好,因為該部分位于pandas_udf為性能而向量化的 a 中。
輸入 df:
import pandas as pd
pdf = pd.DataFrame({
'date': {
0: pd.Timestamp('2021-08-01'),
1: pd.Timestamp('2021-08-01'),
2: pd.Timestamp('2021-08-02'),
3: pd.Timestamp('2021-08-03'),
4: pd.Timestamp('2021-08-03'),
5: pd.Timestamp('2021-08-02'),
6: pd.Timestamp('2021-08-02')
},
'product_nr': {0: '1', 1: '2', 2: '3', 3: '4', 4: '5', 5: '6', 6: '7'},
'Category': {0: 'Cars', 1: 'Cars', 2: 'Cats', 3: 'Dogs', 4: 'Dogs', 5: 'Cats', 6 :'Cats'},
'price': {
0: '34',
1: '24',
2: '244',
3: '284',
4: '274',
5: '354',
6 : '250'
}
})
df = spark.createDataFrame(pdf)
腳本:
from pyspark.sql import functions as F
from itertools import combinations
@F.pandas_udf('array<array<string>>')
def arr_combinations(c: pd.Series) -> pd.Series:
return c.apply(lambda x: list(combinations(x, 2)))
df2 = df.groupBy('Category', 'date').agg(F.collect_list('product_nr').alias('ps'))
df2 = df2.withColumn('ps', F.explode(arr_combinations('ps')))
df2 = df2.select(
'Category', 'date',
F.col('ps')[0].alias('product_nr'),
F.col('ps')[1].alias('product_to_be_compared')
)
df3 = df.join(df2, ['product_nr', 'Category', 'date'])
df3.show()
# ---------- -------- ------------------- ----- ----------------------
# |product_nr|Category| date|price|product_to_be_compared|
# ---------- -------- ------------------- ----- ----------------------
# | 3| Cats|2021-08-02 00:00:00| 244| 7|
# | 3| Cats|2021-08-02 00:00:00| 244| 6|
# | 1| Cars|2021-08-01 00:00:00| 34| 2|
# | 6| Cats|2021-08-02 00:00:00| 354| 7|
# | 4| Dogs|2021-08-03 00:00:00| 284| 5|
# ---------- -------- ------------------- ----- ----------------------
如果您想直接在此表中比較價格,請使用以下命令:
from pyspark.sql import functions as F
from itertools import combinations
@F.pandas_udf('array<array<array<string>>>')
def arr_combinations(c: pd.Series) -> pd.Series:
return c.apply(lambda x: list(combinations(x, 2)))
df2 = df.groupBy('Category', 'date').agg(F.collect_list(F.array('product_nr', 'price')).alias('ps'))
df2 = df2.withColumn('ps', F.explode(arr_combinations('ps')))
df2 = df2.select(
F.col('ps')[0][0].alias('product_nr'),
'Category',
'date',
F.col('ps')[0][1].alias('product_price'),
F.col('ps')[1][0].alias('product_to_be_compared'),
F.col('ps')[1][1].alias('product_to_be_compared_price'),
)
df2.show()
# ---------- -------- ------------------- ------------- ---------------------- ----------------------------
# |product_nr|Category| date|product_price|product_to_be_compared|product_to_be_compared_price|
# ---------- -------- ------------------- ------------- ---------------------- ----------------------------
# | 1| Cars|2021-08-01 00:00:00| 34| 2| 24|
# | 3| Cats|2021-08-02 00:00:00| 244| 6| 354|
# | 3| Cats|2021-08-02 00:00:00| 244| 7| 250|
# | 6| Cats|2021-08-02 00:00:00| 354| 7| 250|
# | 4| Dogs|2021-08-03 00:00:00| 284| 5| 274|
# ---------- -------- ------------------- ------------- ---------------------- ----------------------------
uj5u.com熱心網友回復:
假設每個類別有兩個產品,您可以反轉每個組的值:
df['product_to_be_compared'] = (df.groupby('Category')['product_nr']
.transform(lambda s: s[::-1].values)
)
輸出:
date product_nr Category price product_to_be_compared
0 2021-08-01 1 Cars 34 2
1 2022-08-01 2 Cars 24 1
2 2021-08-02 3 Cats 244 6
3 2021-08-01 4 Dogs 284 5
4 2022-08-01 5 Dogs 274 4
5 2022-08-01 6 Cats 354 3
要交換幾列:
df[['prod2', 'price2']] = (df.groupby('Category')['product_nr', 'price']
.transform(lambda s: s[::-1].values)
)
輸出:
date product_nr Category price prod2 price2
0 2021-08-01 1 Cars 34 2 24
1 2022-08-01 2 Cars 24 1 34
2 2021-08-02 3 Cats 244 6 354
3 2021-08-01 4 Dogs 284 5 274
4 2022-08-01 5 Dogs 274 4 284
5 2022-08-01 6 Cats 354 3 244
更新:在洗掉重復項時鏈接到同一組中的另一個值
m = df.groupby('Category').cumcount().eq(1)
mapper = df[m].set_index('Category')['product_nr']
df[~m].assign(product_to_be_compared=lambda d: d['Category'].map(mapper))
輸出:
date product_nr Category price product_to_be_compared
0 2021-08-01 1 Cars 34 2
2 2021-08-02 3 Cats 244 6
3 2021-08-01 4 Dogs 284 5
6 2022-08-02 7 Cats 250 6
轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/510810.html
上一篇:如何僅從單個表中獲取值
