如何合并含共享列的ROOT DataFrame并保存至同一ROOT文件?
问题描述
我用同事编写的代码模拟事件,输出了一个.root文件。分析时我读取其中的TTree,通过自定义Python函数生成多个numpy数组,再把这些输出转换成独立的ROOT DataFrame。现在想知道:能不能合并这两个包含共享列的DataFrame,得到一个整合了双方数据的DataFrame?如果不可行,另一种方案是把我的列作为分支添加到原ROOT文件的树中。我刚接触ROOT,希望能得到清晰的方案。
最终目标是把我和同事的数据整合到同一个.root文件中。两个DataFrame共享EventNumber列(每个事件唯一)和Asic列(不唯一),这两列无需重复添加,且数据顺序已经对应正确。
相关代码如下:
import ROOT as r import numpy as np import pandas as pd df = r.RDataFrame('tree',"~/FirstOutput.root") board = np.zeros(tree.GetEntries(),dtype='int') column = np.zeros(tree.GetEntries(),dtype='int') ASIC_Column = [] EventNumn = [] for event in range(tree.GetEntries()): tree.GetEntry(event) asic= tree.asic[0] event_Numn = tree.eventNumber ASIC_Column.append(asic) EventNumn.append(event_Numn) board[event] = get_board(asic) column[event] = is_even(asic) # Board和Column是从原DataFrame的Asic列生成的numpy数组 # get_board和is_even用于判断事件在探测器上的位置 d = pd.DataFrame() d['board'] = board d['column'] = column d['asic'] = ASIC_Column d['eventNumber'] = EventNumn data = {key: d[key].values for key in ['eventNumber', 'asic', 'board','column']} rdf = r.RDF.FromNumpy(data)
解决方案
方案一:直接在原RDataFrame上生成新列(最推荐)
你当前的循环读TTree效率很低,ROOT RDataFrame支持直接在原数据集上用Define方法生成新列,无需手动转numpy再新建RDataFrame,一步就能得到整合所有数据的DataFrame,之后直接导出即可。
示例代码:
import ROOT as r # 读取原ROOT文件的树 df = r.RDataFrame('tree', "~/FirstOutput.root") # 定义自定义函数,适配RDataFrame的列数据格式(asic是数组,取第一个元素) def get_board(asic_array): asic = asic_array[0] # 替换成你的实际get_board逻辑 return asic // 10 def is_even(asic_array): asic = asic_array[0] # 替换成你的实际is_even逻辑 return 1 if asic % 2 == 0 else 0 # 在原DataFrame上添加新列 df_with_new_cols = df.Define("board", get_board, ["asic"])\ .Define("column", is_even, ["asic"]) # 导出到新的ROOT文件,包含所有原列和新列 df_with_new_cols.Snapshot("tree", "MergedOutput.root")
方案二:合并两个已有的RDataFrame
如果你已经生成了两个独立的RDataFrame(原df和自己创建的rdf),可以通过Join操作合并,用唯一标识eventNumber作为连接键:
# 先移除自己生成的rdf中重复的列(比如asic),避免合并后重复 rdf_clean = rdf.DropColumns(["asic"]) # 以eventNumber为键合并两个DataFrame merged_df = df.Join(rdf_clean, "eventNumber") # 导出整合后的数据集到新文件 merged_df.Snapshot("tree", "MergedOutput.root")
方案三:将新列添加到原ROOT文件的树中
如果需要直接给原树添加分支(或生成包含原树+新分支的新文件),可以直接操作TTree:
import ROOT as r import numpy as np # 打开原文件(只读模式) input_file = r.TFile("~/FirstOutput.root", "READ") tree = input_file.Get("tree") # 新建输出文件 output_file = r.TFile("UpdatedOutput.root", "RECREATE") # 复制原树的结构,但不复制数据 new_tree = tree.CloneTree(0) # 定义要添加的分支变量 board = np.zeros(1, dtype='int') column = np.zeros(1, dtype='int') # 给新树添加分支 new_tree.Branch("board", board, "board/I") new_tree.Branch("column", column, "column/I") # 遍历原树,计算并填充新分支 for event in tree: asic = event.asic[0] board[0] = get_board(asic) column[0] = is_even(asic) new_tree.Fill() # 写入数据并关闭文件 new_tree.Write() output_file.Close() input_file.Close()
内容的提问来源于stack exchange,提问作者LostPhysicsGradStudent
相关产品推荐
相关产品推荐

