0

我是编程和 ROOT (CERN) 的新手,所以请放轻松。简单地说,我想将一个 ~900 MB(11M 行 x 10 列)的 .csv 文件转换成一个组织良好的 .root TTree。有人可以提供最好的方法吗?

这是带有标题的示例数据行(它是 2010 年美国人口普查区人口和人口密度数据):

"人口普查县代码","人口普查区域代码","人口普查街区代码","县/州","街区质心纬度 (度)","街区质心 W 经度 (度)","街区土地面积 (sq mi )","街区土地面积(平方公里)","街区人口","街区人口密度(人/平方公里)"

1001,201,1000,Autauga AL,32.469683,-86.480959,0.186343,0.482626154,61,126.3918241

我已经粘贴了我到目前为止所写的内容。

运行时我特别无法弄清楚这个错误:“C:41:1:错误:未知类型名称'UScsvToRoot'”。

这可能真的很愚蠢,但是您如何在 ROOT 中读取字符串(用于读取县/州名称)?比如数据类型是什么?我只需要使用char吗?我在发呆。

#include "Riostream.h"
#include "TString.h"
#include "TFile.h"
#include "TNtuple.h"
#include "TSystem.h"

void UScsvToRoot() {

   TString dir = gSystem->UnixPathName(__FILE__);
   dir.ReplaceAll("UScsvToRoot.C","");
   dir.ReplaceAll("/./","/");
   ifstream in;
   in.open(Form("%sUSPopDens.csv",dir.Data()));

   Int_t countyCode,tractCode,blockCode;
   // how to import County/State string?
   Float_t lat,long,areaMi,areaKm,pop,popDens;
   Int_t nlines = 0;
   TFile *f = new TFile("USPopDens.root","RECREATE");
   TNtuple *ntuple = new TNtuple("ntuple","data from csv file","countyCode:tractCode:blockCode:countyState:lat:long:areaMi:areaKm:pop:popDens");

   while (1) {
      in >> countyCode >> tractCode >> blockCode >> countyState >> lat >> long >> areaMi >> areaKm >> pop >> popDens;
      if (!in.good()) break;
      ntuple->Fill(countyCode,tractCode,blockCode,countyState,lat,long,areaMi,areaKm,pop,popDens);
      nlines++;
   }

   in.close();

   f->Write();
}`
4

3 回答 3

3

好的,所以我要试一试,但前面有一些评论:

关于root的问题,你应该强烈考虑去root主页,然后再去论坛。虽然 stackoverflow 是一个很好的信息来源,但关于根框架的特定问题更适合在根主页上。

如果你是 root 新手,你应该看看教程页面;它有许多关于如何使用 root 的各种功能的示例。

您还应该使用包含所有根类文档的根参考指南。

对于您的代码:如果您查看正在使用的类的文档TNtuple,您会在描述中看到它清楚地表明:

一棵仅限于浮点变量列表的简单树。

所以试图将任何字符串存储到 aTNtuple中都行不通。您需要为此使用更通用的类TTree

要读取文件并将信息存储在树中,您有两种选择:手动定义分支,然后在循环文件时填充树:

void UScsvToRoot() {
   TString dir = gSystem->UnixPathName(__FILE__);
   dir.ReplaceAll("UScsvToRoot.C","");
   dir.ReplaceAll("/./","/");
   ifstream in;
   in.open(Form("%sUSPopDens.csv",dir.Data()));

   Int_t countyCode,tractCode,blockCode;
   char countyState[1024];
   Float_t lat,lon,areaMi,areaKm,pop,popDens;
   Int_t nlines = 0;
   TFile *f = new TFile("USPopDens.root","RECREATE");
   TTree *tree = new TTree("ntuple","data from csv file");

   tree->Branch("countyCode",&countyCode,"countyCode/I");
   tree->Branch("tractCode",&tractCode,"tractCode/I");
   tree->Branch("blockCode",&blockCode,"blockCode/I");
   tree->Branch("countyState",countyState,"countyState/C");
   tree->Branch("lat",&lat,"lat/F");
   tree->Branch("long",&lon,"lon/F");
   tree->Branch("areaMi",&areaMi,"areaMi/F");
   tree->Branch("areaKm",&areaKm,"areaKm/F");
   tree->Branch("pop",&pop,"pop/F");
   tree->Branch("popDens",&popDens,"popDens/F");

   while (1) {
      in >> countyCode >> tractCode >> blockCode >> countyState >> lat >> lon >> areaMi >> areaKm >> pop >> popDens;
      if (!in.good()) break;
      tree->Fill();
      nlines++;
   }

   in.close();

   f->Write();
}

该命令TTree::Branch基本上告诉root

  • 您的分支名称
  • root 将从中读取信息的变量的地址
  • 分支的格式

TBranch包含字符串信息的类型是C如果您查看TTree 文档意味着

  • C : 以 0 字符结尾的字符串

注意我给了字符数组一定的大小,你应该看看自己适合你的数据的大小。

您可以使用的另一种可能性是取消 ifstream 并简单地使用您将采用的ReadFile方法TTree

#include "Riostream.h"
#include "TString.h"
#include "TFile.h"
#include "TTree.h"
#include "TSystem.h"

void UScsvToRoot() {

   TString dir = gSystem->UnixPathName(__FILE__);
   dir.ReplaceAll("UScsvToRoot.C","");
   dir.ReplaceAll("/./","/");

   TFile *f = new TFile("USPopDens.root","RECREATE");
   TTree *tree = new TTree("ntuple","data from csv file");
   tree->ReadFile("USPopDens.csv","countyCode/I:tractCode/I:blockCode/I:countyState/C:lat/F:lon/F:areaMi/F:areaKm/F:pop/F:popDens/F",',');
   f->Write();
}

您可以阅读根用户指南中有关 TTress 的部分以获取更多信息;除其他外,它还有一个使用 TTree:ReadFile 的示例

让我知道这是否有帮助

于 2015-07-24T13:38:58.463 回答
1

我认为您最好只使用root_pandas。在@Erik 的综合答案中,您最终仍然手动指定感兴趣的变量(countryCode/I,...)。哪个有其优点(我只是列出通用的:你知道你会得到什么。如果缺少预期的变量,会出现错误消息,)。但另一方面,它让您有机会引入拼写错误,如果您阅读多个 csv 文件,您将不会注意到其中任何一个有更多变量……最终复制变量名称和确定变量类型是计算机应该非常好的事情在。

在 root_pandas 你的代码应该是这样的

import pandas
df = pandas.read_csv("USPopDens.csv")
from root_pandas import readwrite
df.to_root("USPopDens.root")
于 2018-02-22T20:00:49.577 回答
0

我想强调 Erik 的回答中的一个细节:在 TTree 之前创建 TFile 的事实对程序产生的根文件的大小有影响。我正在处理类似的问题(需要将 ~1 GB 的 CSV 文件读取到根树中并保存到文件中,但首先创建了 TTree,然后创建了 TFile 来存储树。生成的根文件比先创建 TTree 再创建 TFile 时大 10 倍。

出现这种行为的原因是 TTree 中分支的压缩比不同。基本上,如果将树写入内存,则不会应用压缩,而将树写入磁盘时会应用更高的压缩比。

参考:https ://root-forum.cern.ch/t/ttree-compression-factor-1-00/31850/11

于 2019-12-22T04:46:43.070 回答