Python 在Spark中将大型文本/pgn文件转换为JSON
我需要将PGN文件转换为JSON,这样我就可以使用Spark将它们转换为Spark数据帧,并最终创建一个图形。我已经编写了一个python脚本,使用Pandas将它们解析为数据帧,但速度太慢了(170k游戏大约需要56分钟(最初估计为30分钟,但在配置文件之后我估计需要56分钟))。我还尝试使用这个repo:它给了我JSON文件,但170k游戏用了69分钟 我可以将PGN扩展名改为.txt,它的工作原理似乎完全相同,因此我假设有更多的支持.txt到JSON,但我不确定 我认为Spark将比“普通”Python更快,但我不知道如何进行转换。下面是一个示例。虽然有20亿个游戏,但我目前的方法都不起作用,因为如果我使用PGN-to-JSON解析器,需要将近2年的时间。理想情况下,使用.txt触发数据帧并完全忽略JSON将是理想的选择Python 在Spark中将大型文本/pgn文件转换为JSON,python,json,apache-spark,pyspark,distributed-computing,Python,Json,Apache Spark,Pyspark,Distributed Computing,我需要将PGN文件转换为JSON,这样我就可以使用Spark将它们转换为Spark数据帧,并最终创建一个图形。我已经编写了一个python脚本,使用Pandas将它们解析为数据帧,但速度太慢了(170k游戏大约需要56分钟(最初估计为30分钟,但在配置文件之后我估计需要56分钟))。我还尝试使用这个repo:它给了我JSON文件,但170k游戏用了69分钟 我可以将PGN扩展名改为.txt,它的工作原理似乎完全相同,因此我假设有更多的支持.txt到JSON,但我不确定 我认为Spark将比“普通
[Event "Rated Classical game"]
[Site "https://lichess.org/j1dkb5dw"]
[White "BFG9k"]
[Black "mamalak"]
[Result "1-0"]
[UTCDate "2012.12.31"]
[UTCTime "23:01:03"]
[WhiteElo "1639"]
[BlackElo "1403"]
[WhiteRatingDiff "+5"]
[BlackRatingDiff "-8"]
[ECO "C00"]
[Opening "French Defense: Normal Variation"]
[TimeControl "600+8"]
[Termination "Normal"]
1. e4 e6 2. d4 b6 3. a3 Bb7 4. Nc3 Nh6 5. Bxh6 gxh6 6. Be2 Qg5 7. Bg4 h5 8. Nf3 Qg6 9. Nh4 Qg5 10. Bxh5 Qxh4 11. Qf3 Kd8 12. Qxf7 Nc6 13. Qe8# 1-0
编辑:添加了20k游戏的配置文件
ncalls tottime percall cumtime percall filename:lineno(function)
1 26.828 26.828 395.848 395.848 /Users/danieljones/Documents – Daniel’s iMac/GitHub/ST446Project/ParsePGN.py:11(parse_pgn)
20000 0.798 0.000 289.203 0.014 /Users/danieljones/opt/anaconda3/envs/LSE/lib/python3.6/site-packages/pandas/core/frame.py:7614(append)
20000 0.098 0.000 199.489 0.010 /Users/danieljones/opt/anaconda3/envs/LSE/lib/python3.6/site-packages/pandas/core/reshape/concat.py:70(concat)
20000 0.480 0.000 126.548 0.006 /Users/danieljones/opt/anaconda3/envs/LSE/lib/python3.6/site-packages/pandas/core/reshape/concat.py:295(__init__)
100002 0.212 0.000 122.178 0.001 /Users/danieljones/opt/anaconda3/envs/LSE/lib/python3.6/site-packages/pandas/core/generic.py:5199(_protect_consolidate)
80002 0.076 0.000 122.177 0.002 /Users/danieljones/opt/anaconda3/envs/LSE/lib/python3.6/site-packages/pandas/core/generic.py:5210(_consolidate_inplace)
40000 0.079 0.000 122.063 0.003 /Users/danieljones/opt/anaconda3/envs/LSE/lib/python3.6/site-packages/pandas/core/generic.py:5218(_consolidate)
80002 0.170 0.000 121.830 0.002 /Users/danieljones/opt/anaconda3/envs/LSE/lib/python3.6/site-packages/pandas/core/generic.py:5213(f)
100001 0.223 0.000 99.829 0.001 /Users/danieljones/opt/anaconda3/envs/LSE/lib/python3.6/site-packages/pandas/core/internals/managers.py:986(_consolidate_inplace)
59999 0.451 0.000 96.718 0.002 /Users/danieljones/opt/anaconda3/envs/LSE/lib/python3.6/site-packages/pandas/core/internals/managers.py:1898(_consolidate)
80002 0.138 0.000 96.599 0.001 /Users/danieljones/opt/anaconda3/envs/LSE/lib/python3.6/site-packages/pandas/core/internals/managers.py:970(consolidate)
79999 52.602 0.001 91.913 0.001 /Users/danieljones/opt/anaconda3/envs/LSE/lib/python3.6/site-packages/pandas/core/internals/managers.py:1915(_merge_blocks)
20000 7.432 0.000 79.741 0.004 /Users/danieljones/opt/anaconda3/envs/LSE/lib/python3.6/site-packages/chess/pgn.py:1323(read_game)
20000 0.361 0.000 72.843 0.004 /Users/danieljones/opt/anaconda3/envs/LSE/lib/python3.6/site-packages/pandas/core/reshape/concat.py:456(get_result)
我不确定“cumtime”是否是最好的排序列,但似乎追加步骤需要花费很多时间
这是我的剧本:
def parse_pgn(pgn):
games = []
i = 0
edges_df = pd.DataFrame(columns=["Event", "Round", "WhitePlayer", "BlackPlayer", "Result", "BlackElo",
"Opening", "TimeControl", "Date", "Time", "WhiteElo"])
while i < 20000:
first_game = chess.pgn.read_game(pgn)
if first_game is not None:
Event = first_game.headers["Event"]
Round = first_game.headers["Round"]
White_player = first_game.headers["White"]
Black_player = first_game.headers["Black"]
Result = first_game.headers["Result"] # Add condition to split this
if Result == "1-0":
Result = White_player
elif Result == "0-0":
Result = "Draw"
else:
Result = Black_player
BlackELO = first_game.headers["BlackElo"]
Opening = first_game.headers["Opening"]
TimeControl = first_game.headers["TimeControl"]
UTCDate = first_game.headers["UTCDate"]
UTCTime = first_game.headers["UTCTime"]
WhiteELO = first_game.headers["WhiteElo"]
edges_df = edges_df.append({"Event": Event,
"Round": Round,
"WhitePlayer": White_player,
"BlackPlayer": Black_player,
"Result": Result,
"BlackElo": BlackELO,
"Opening": Opening,
"TimeControl": TimeControl,
"Date": UTCDate,
"Time": UTCTime,
"White": WhiteELO,
}, ignore_index=True)
games.append(first_game)
i += 1
else:
pass
return edges_df
def parse_pgn(pgn):
游戏=[]
i=0
edges_df=pd.DataFrame(列=[“事件”、“回合”、“白玩家”、“黑玩家”、“结果”、“黑玩家”,
“开始”、“时间控制”、“日期”、“时间”、“怀特洛”])
当我<20000时:
first_game=chess.pgn.read_game(pgn)
如果first_game不是None:
事件=第一场比赛。标题[“事件”]
回合=第一局。头球[“回合”]
白人玩家=第一场比赛。头球[“白人”]
黑色玩家=第一局。头球[“黑色”]
结果=第一个游戏。标题[“结果”]#添加拆分此游戏的条件
如果结果==“1-0”:
结果=白人球员
elif结果==“0-0”:
结果=“绘制”
其他:
结果=黑棋手
布莱克洛=第一场比赛。头球[“布莱克洛”]
开局=第一局比赛。头球[“开局”]
TimeControl=第一个游戏标题[“TimeControl”]
UTCDate=第一个游戏标题[“UTCDate”]
UTCTime=第一个游戏标题[“UTCTime”]
WhiteELO=第一场比赛。标题[“WhiteELO”]
edges_df=edges_df.append({“Event”:事件,
“圆”:圆,
“白人玩家”:白人玩家,
“黑人玩家”:黑人玩家,
“结果”:结果,
“BlackElo”:BlackElo,
“开放”:开放,
“时间控制”:时间控制,
“日期”:UTCDate,
“时间”:UTCTime,
“白色”:怀特埃洛,
},忽略_index=True)
games.append(第一个游戏)
i+=1
其他:
通过
返回边
编辑2:将追加方法更改为字典。20k现在需要78秒。许多花费时间的方法似乎都来自于
国际象棋
软件包,比如检查合法的移动,阅读棋盘布局。所有这些对我的最终目标都不重要,所以我想知道我是否可以放弃使用这个软件包,自己将文件分割成不同的游戏,也许在[Event
因为这是每个不同游戏的开始。不要。将附加到pandas.DataFrame
循环中如果你想有较短的运行时间,你可以阅读更多关于这方面的内容。你可以先将dict
存储在iterable中,然后从中创建pandas.DataFrame
。我会使用collections.deque
(来自系列
内置模块)由于其设计用于运动高速。附加
,让我们比较这些不同的方式
import collections
import pandas as pd
def func1():
df = pd.DataFrame(columns=['x','y','z'])
for i in range(1000):
df = df.append({'x':i,'y':i*10,'z':i*100}, ignore_index=True)
return df
def func2():
store = collections.deque()
for i in range(1000):
store.append({'x':i,'y':i*10,'z':i*100})
df = pd.DataFrame(store, columns=['x','y','z'])
return df
这些函数产生相等的pandas.DataFrame
s,我使用内置模块timeit
以如下方式比较了它们
import timeit
print(timeit.timeit('func1()',number=10,globals={'func1':func1}))
print(timeit.timeit('func2()',number=10,globals={'func2':func2}))
结果如下
18.370871236000312
0.02604325699940091
速度快了500多倍。当然,您的里程数可能会有所不同,但我建议您尝试进行此优化。已经编写了一个python脚本,使用Pandas将它们解析为数据帧,但速度太慢(170k游戏大约需要30分钟)。您尝试过评测或优化代码吗?非常好的主意,谢谢。我已将此添加为编辑。