我是编程和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();
}`
答案 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
包含字符串信息的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