Python 使用pyspark对多个文件进行排序
我有股票数据(超过6000只股票,100+GB)保存为HDF5文件 基本上,我正在尝试将这个pandas代码翻译成pyspark。理想情况下,我希望将用于排名的值以及排名本身保存到文件中Python 使用pyspark对多个文件进行排序,python,apache-spark,pyspark,Python,Apache Spark,Pyspark,我有股票数据(超过6000只股票,100+GB)保存为HDF5文件 基本上,我正在尝试将这个pandas代码翻译成pyspark。理想情况下,我希望将用于排名的值以及排名本身保存到文件中 agg_df = pd.DataFrame() for stock in stocks: df = pd.read_csv(stock) df = my_func(df) # custom function, output of which will be used for ranking. F
agg_df = pd.DataFrame()
for stock in stocks:
df = pd.read_csv(stock)
df = my_func(df) # custom function, output of which will be used for ranking. For simplicity, can use standard deviation
agg_df = pd.concat([agg_df, df], ax=1) # row-wise concat
agg_df.rank() #.to_csv() <- would like to save ranks for future use
所需输出(其中每个数字都是一个秩):
我阅读了关于Window和pyspark.sql的其他答案,但不确定如何将它们应用到我的案例中,因为我需要在排名前按行汇总这些答案(至少在pandas中)
编辑1:在我将数据读取到rddrdd=sc.parallelize(data.keys).map(data.read_data)
之后,rdd变成了一个管道rdd,它没有.select()方法。0xDFDF的示例包含一个数据帧中的所有数据,但我认为将所有数据都附加到一个数据帧中进行计算不是一个好主意
结果:终于解决了这个问题。有两个问题:读取文件和执行计算
关于读取文件,我最初使用rdd=sc.parallelize(data.keys).map(data.read_data)
从HDF5加载它们,这导致了PipelineRDD,这是一组数据帧。这些需要转换为spark数据帧,以便解决方案能够工作。我最终将我的hdf5文件转换为拼花地板,并将它们保存到一个单独的文件夹中。然后使用
sqlContext = pyspark.sql.SQLContext(sc)
rdd_p = sqlContext.read.parquet(r"D:\parq")
将所有文件读取到数据帧
然后根据接受的答案进行计算。非常感谢0xDFDF的帮助
额外费用:
讨论-
0xDFDFDF解决方案-事实上,windows函数将起到作用。 我已经创建了一个小的模拟数据集,它应该与您的类似
columns = ['DateTime', 'Symbol', 'Open', 'High', 'Low', 'Close', 'Volume']
data = [('2010-09-13 09:30:00','A',29.23,29.25,29.17,29.25,17667.0),
('2010-09-13 09:31:00','A',29.26,29.34,29.25,29.33,5000.0),
('2010-09-13 09:32:00','A',29.31,29.36,29.31,29.36,600.0),
('2010-09-13 09:34:00','A',29.35,29.39,29.31,29.39,3222.0),
('2010-09-13 09:30:00','AAPL',39.23,39.25,39.17,39.25,37667.0),
('2010-09-13 09:31:00','AAPL',39.26,39.34,39.25,39.33,3000.0),
('2010-09-13 09:32:00','AAPL',39.31,39.36,39.31,39.36,300.0),
('2010-09-13 09:33:00','AAPL',39.33,39.36,39.30,39.35,3300.0),
('2010-09-13 09:34:00','AAPL',39.35,39.39,39.31,39.39,4222.0),
('2010-09-13 09:34:00','MSFT',39.35,39.39,39.31,39.39,7222.0)]
df = spark.createDataFrame(data, columns)
现在,df.show()
+-------------------+------+-----+-----+-----+-----+-------+
| DateTime|Symbol| Open| High| Low|Close| Volume|
+-------------------+------+-----+-----+-----+-----+-------+
|2010-09-13 09:30:00| A|29.23|29.25|29.17|29.25|17667.0|
|2010-09-13 09:31:00| A|29.26|29.34|29.25|29.33| 5000.0|
|2010-09-13 09:32:00| A|29.31|29.36|29.31|29.36| 600.0|
|2010-09-13 09:34:00| A|29.35|29.39|29.31|29.39| 3222.0|
|2010-09-13 09:30:00| AAPL|39.23|39.25|39.17|39.25|37667.0|
|2010-09-13 09:31:00| AAPL|39.26|39.34|39.25|39.33| 3000.0|
|2010-09-13 09:32:00| AAPL|39.31|39.36|39.31|39.36| 300.0|
|2010-09-13 09:33:00| AAPL|39.33|39.36| 39.3|39.35| 3300.0|
|2010-09-13 09:34:00| AAPL|39.35|39.39|39.31|39.39| 4222.0|
|2010-09-13 09:34:00| MSFT|39.35|39.39|39.31|39.39| 7222.0|
+-------------------+------+-----+-----+-----+-----+-------+
下面是解决方案,它使用前面提到的rank()
窗口函数。需要进行一些转换,可以使用pivot()
函数进行转换
from pyspark.sql.window import Window
import pyspark.sql.functions as f
result = (df
.select(
'DateTime',
'Symbol',
f.rank().over(Window().partitionBy('DateTime').orderBy('Volume')).alias('rank')
)
.groupby('DateTime')
.pivot('Symbol')
.agg(f.first('rank'))
.orderBy('DateTime')
)
通过调用result.show()
您将得到:
+-------------------+----+----+----+
| DateTime| A|AAPL|MSFT|
+-------------------+----+----+----+
|2010-09-13 09:30:00| 1| 2|null|
|2010-09-13 09:31:00| 2| 1|null|
|2010-09-13 09:32:00| 2| 1|null|
|2010-09-13 09:33:00|null| 1|null|
|2010-09-13 09:34:00| 1| 2| 3|
+-------------------+----+----+----+
确保您理解rank()
、densite\u rank()
和row\u number()
函数之间的区别,因为它们在给定窗口中遇到相等的数字时表现不同-您可以找到解释。非常感谢您的回答。我将尝试实现您的代码。在你的回答中,你是否按成交量对股票进行了排名?我如何应用我的自定义函数/另一个度量?是的,它是按体积排序的。如果你想实现你的功能,你需要一个用户定义的功能(UDF)。您可以在此处找到一个示例:。但是,它们在Python中可能速度较慢,因此您可能对将代码移植到Scala感兴趣,因为在Scala中,UDF不会遇到性能问题。祝你好运我不知道如何实施它。我的rdd是pipelineRDD,它是pandas.DataFrames的集合。我不知道如何转换/应用您的解决方案pipelineRDD@Biarys这是一个不同的API。您可以使用rdd.toDF()方法从rdd转换为DF。随后使用df.printSchema()检查类型,因为有些类型可能需要强制转换。
from pyspark.sql.window import Window
import pyspark.sql.functions as f
result = (df
.select(
'DateTime',
'Symbol',
f.rank().over(Window().partitionBy('DateTime').orderBy('Volume')).alias('rank')
)
.groupby('DateTime')
.pivot('Symbol')
.agg(f.first('rank'))
.orderBy('DateTime')
)
+-------------------+----+----+----+
| DateTime| A|AAPL|MSFT|
+-------------------+----+----+----+
|2010-09-13 09:30:00| 1| 2|null|
|2010-09-13 09:31:00| 2| 1|null|
|2010-09-13 09:32:00| 2| 1|null|
|2010-09-13 09:33:00|null| 1|null|
|2010-09-13 09:34:00| 1| 2| 3|
+-------------------+----+----+----+