从熊猫数据框创建一个火花数据框
import pandas as pd
df = pd.DataFrame({"b": ['A','A','A','A','B', 'B','B','C','C','D','D', 'D','D','D','D','D','D','D','D','D'],"Sno": [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20],"a": [3,-4,2, -1, -3, -1,-7,-6, 1, 1, -1, 1,4,5,-3,2,3,4, -1, -2]})
df2=spark.createDataFrame(df)
接下来,我在字段'b'上使用窗口分区
from pyspark.sql import window
win_spec = (window.Window.partitionBy(['b']).orderBy("Sno").rowsBetween(window.Window.unboundedPreceding, 0))
根据值添加一个正值,负值字段,并创建一个lambda函数
df2 = df2.withColumn("pos_neg",col("a") <0)
pos_neg_func =udf(lambda x: ((x) & (x != x.shift())).cumsum())
尝试创建新列(该计数器是负值的计数器,但在变量'b'中。因此,当'b'中的字段更改时,计数器重新启动。此外,如果存在连续的-ve值,则应将它们视为a单值,计数器变化1
df3 = (df2.select('pos_neg',pos_neg_func('pos_neg').alias('val')))
我希望输出为
b Sno a val val_2
0 A 1 3 False 0
1 A 2 -4 True 1
2 A 3 2 False 1
3 A 4 -1 True 2
4 B 5 -3 True 1
5 B 6 -1 True 1
6 B 7 -7 True 1
7 C 8 -6 True 1
8 C 9 1 False 1
9 D 10 1 False 0
10 D 11 -1 True 1
11 D 12 1 False 1
12 D 13 4 False 1
13 D 14 5 False 1
14 D 15 -3 True 2
15 D 16 2 False 2
16 D 17 3 False 2
17 D 18 4 False 2
18 D 19 -1 True 3
19 D 20 -2 True 3
在python中,一个简单的函数如下所示:
df['val'] = df.groupby('b')['pos_neg'].transform(lambda x: ((x) & (x != x.shift())).cumsum())
josh-friedlander在上面的代码中提供了支持
答案 0 :(得分:1)
Pyspark没有移位功能,但是您可以使用lag窗口功能,该功能为您提供当前行之前的行。如果val
列的值为pos_neg
并且前一个True
的值为{,则第一个窗口(称为w)将pos_neg
列的值设置为1。 {1}},否则为0。
在第二个窗口(称为w2)中,我们计算出累加和以获得所需的
False
输出:
import pandas as pd
import pyspark.sql.functions as F
from pyspark.sql import Window
df = pd.DataFrame({"b": ['A','A','A','A','B', 'B','B','C','C','D','D', 'D','D','D','D','D','D','D','D','D'],"Sno": [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20],"a": [3,-4,2, -1, -3, -1,-7,-6, 1, 1, -1, 1,4,5,-3,2,3,4, -1, -2]})
df2=spark.createDataFrame(df)
w = Window.partitionBy('b').orderBy('Sno')
w2 = Window.partitionBy('b').rowsBetween(Window.unboundedPreceding, 0).orderBy('Sno')
df2 = df2.withColumn("pos_neg",col("a") <0)
df2 = df2.withColumn('val', F.when((df2.pos_neg == True) & (F.lag('pos_neg', default=False).over(w) == False), 1).otherwise(0))
df2 = df2.withColumn('val', F.sum('val').over(w2))
df2.show()
您可能想知道为什么必须有一个列来允许我们对数据集进行排序。让我尝试用一个例子来解释一下。熊猫读取了以下数据,并为其分配了索引(左列)。您想计算+---+---+---+-------+---+
|Sno| a| b|pos_neg|val|
+---+---+---+-------+---+
| 5| -3| B| true| 1|
| 6| -1| B| true| 1|
| 7| -7| B| true| 1|
| 10| 1| D| false| 0|
| 11| -1| D| true| 1|
| 12| 1| D| false| 1|
| 13| 4| D| false| 1|
| 14| 5| D| false| 1|
| 15| -3| D| true| 2|
| 16| 2| D| false| 2|
| 17| 3| D| false| 2|
| 18| 4| D| false| 2|
| 19| -1| D| true| 3|
| 20| -2| D| true| 3|
| 8| -6| C| true| 1|
| 9| 1| C| false| 1|
| 1| 3| A| false| 0|
| 2| -4| A| true| 1|
| 3| 2| A| false| 1|
| 4| -1| A| true| 2|
+---+---+---+-------+---+
中True
的出现,而不想计算连续pos_neg
的消耗。该逻辑导致进入True
列,如下所示:
val2
...但是取决于它从熊猫(行顺序)获得的索引。当您更改行的顺序(以及相应的熊猫索引)时,将逻辑应用于同一行时,您会得到不同的结果,只是因为顺序不同:
b Sno a pos_neg val_2
0 A 1 3 False 0
1 A 2 -4 True 1
2 A 3 2 False 1
3 A 4 -1 True 2
4 A 5 -5 True 2
您看到行的顺序很重要。您可能现在想知道pyspark为什么不像pandas那样创建索引。这是因为spark将您的数据保留在群集中分布的几个分区中,并且甚至取决于您的数据源,甚至能够读取分布式数据。因此,在读取数据期间无法添加索引。您可以在使用monotonically_increasing_id函数读取数据后添加一个,但是由于读取过程,数据与数据源的顺序可能已经不同。
您的 b Sno a pos_neg val_2
0 A 1 3 False 0
1 A 3 2 False 0
2 A 2 -4 True 1
3 A 4 -1 True 1
4 A 5 -5 True 1
列避免了此问题,并保证对于相同的数据(确定性),您将始终获得相同的结果。