将900 MB .csv转换为ROOT(CERN)TTree

时间:2015-07-15 01:50:16

标签: c++ csv bigdata root-framework

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

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

"人口普查县法典","人口普查法典","人口普查区块代码","县/州"," ;块质心纬度(度)","块质心W经度(度)","块土地面积(平方英里)","块土地面积(平方公里)","街区人口","街区人口密度(人/平方公里)"

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

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

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

这可能真的很愚蠢,但你怎么读ROOT中的字符串(用县/州名读取)?喜欢什么是数据类型?我只需要使用char's吗?我在消隐。

#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();
}`

3 个答案:

答案 0 :(得分:2)

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

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

如果您是root用户,则应该查看tutorial page;它有很多关于如何使用root的各种功能的例子。

您还应该使用包含所有根类的文档的root reference guide

要使用您的代码:如果您查看正在使用的类TNtuple的{​​{3}},请在说明中明确说明:

  

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

因此尝试将任何字符串存储到TNtuple中都不起作用。您需要使用更通用的类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类型,如果您查看documentation表示

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

N.B。我给了字符数组一定的大小,你应该看到自己适合你的数据的大小。

您可以使用的另一种可能性是取消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();
}

您可以阅读TTree documentation了解更多信息;在许多其他事情中它也有section on TTress in the root users guide on

如果有帮助,请告诉我

答案 1 :(得分: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")

答案 2 :(得分:0)

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

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

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