<jupyter_start><jupyter_text>DataFrame: Functional Chains for [TTrees](https://root.cern.ch/doc/master/classTTree.html) in Python.The DataFrame class brings the feature called functional chains with caching to trees. This is achieved in identifying different functions are creating lists of transformations. Usability is a key. Functional chains are a lot simpler way of creating histograms because the user doesn't need to create loops. DataFrame will do it for you.  PreparationWe include ROOT, DataFrame and PyTreeReader class. DataFrame uses PyTreeReader for filling histograms and filtering results. All of the computing is mostly done by using PyTreeReader inside the DataFrame Class. Clearly this will be done in a better way now that the usage of PyTreeReader in ROOT is still unknown. PyTreeReader can be found from https://github.com/dpiparo/pytreereader<jupyter_code>import ROOT
from PyTreeReader import PyTreeReader
from functional import DataFrame
from ROOT import TFile<jupyter_output><empty_output><jupyter_text>This is to get a tree from test data called cernstaff.root<jupyter_code>testFile = TFile('cernstaff.root')
testTree = testFile.Get('T')<jupyter_output><empty_output><jupyter_text>Here we create the DataFrame object<jupyter_code>dataFrame = DataFrame(testTree)<jupyter_output>Creating the PyTreeReader<jupyter_text>As you can see, it also creates a PyTreeReader. This is why PyTreeReader is mandatory for the class  Traditional read without cache<jupyter_code>%%time
dataFrame.filter(lambda e : e.Children() > 4).head(5)<jupyter_output><empty_output><jupyter_text>Same but now first caching it and then rerunning the same<jupyter_code>dataFrame.resetcache()
%%time
dataFrame.filter(lambda e : e.Children() > 4).cache().head(5)<jupyter_output><empty_output><jupyter_text>Now rerunning it and using the cached results to print<jupyter_code>%%time
dataFrame.filter(lambda e : e.Children() > 4).cache().filter(lambda e : e.Age() < 47).head(5)<jupyter_output><empty_output><jupyter_text>There is some caching with the files in the Swan service, but the point is that first and second run differ alot with their speed  Lets reset the cache by calling a function from the class<jupyter_code>dataFrame.resetcache()<jupyter_output><empty_output><jupyter_text>Now we can demonstrate different histograms and drawing them<jupyter_code>%%time
dataFrame.filter(lambda e : e.Age() > 45).cache().histo('Age:Cost').Draw('COLZ')
ROOT.gPad.Draw()<jupyter_output>Cached FILTER
new cache = True
CPU times: user 28.9 ms, sys: 17.6 ms, total: 46.6 ms
Wall time: 40.3 ms<jupyter_text>Rerun the same analysis, compare the time<jupyter_code>%%time
dataFrame.filter(lambda e : e.Age() > 45).cache().histo('Age:Cost').Draw('COLZ')
ROOT.gPad.Draw()<jupyter_output>Cached FILTER
new cache = False
CPU times: user 19.9 ms, sys: 7.36 ms, total: 27.3 ms
Wall time: 24.8 ms<jupyter_text>Lets add one more filter after the cache and see how it differs...<jupyter_code>%%time
dataFrame.filter(lambda e : e.Age() > 45).cache().filter(lambda e: e.Cost() > 8500).histo('Age:Cost').Draw('COLZ')
ROOT.gPad.Draw()<jupyter_output>Cached FILTER
new cache = False
CPU times: user 20.5 ms, sys: 7.13 ms, total: 27.6 ms
Wall time: 23.4 ms
{'fraction_non_alphanumeric': 0.09726538222498446, 'fraction_numerical': 0.01678060907395898, 'mean_word_length': 6.233707865168539, 'pattern_counts': {'":': 0, '<': 38, '<?xml version=': 0, '>': 44, 'https://': 2, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '10', 'dir': 'jupyter-structured-clean-dedup', 'id': '404134', 'license': 'MIT', 'n_tokens_mistral': 1080, 'n_tokens_neox': 1004, 'n_words': 341, 'path': 'functional/Example_01.ipynb', 'repo_name': 't2vuka00/summerstudentProtoWork', 'size': '3218'}