Choosing between pandas, OOP classes, and dicts (Python)
<p>I have written a program that reads a couple of .csv files (they are not large, a couple of thousands rows each), I do some data cleaning and wrangling and this is the final structure of each .csv file looks (fake data for illustration purposes only).</p>

<pre><code>import pandas as pd
data = [[112233,'Rob',99],[445566,'John',88]]
managers = pd.DataFrame(data)
managers.columns = ['ManagerId','ManagerName','ShopId']
print managers

   ManagerId ManagerName  ShopId
0     112233         Rob      99
1     445566        John      88


data = [[99,'Shop1'],[88,'Shop2']]
shops = pd.DataFrame(data)
shops.columns = ['ShopId','ShopName']
print shops

   ShopId ShopName
0      99    Shop1
1      88    Shop2

data = [[99,2000,3000,4000],[88,2500,3500,4500]]
sales = pd.DataFrame(data)
sales.columns = ['ShopId','Year2010','Year2011','Year2012']
print sales

   ShopId  Year2010  Year2011  Year2012
0      99      2000      3000      4000
1      88      2500      3500      4500
</code></pre>

<p>Then I use <code>xlsxwriter</code> and <code>reportlab</code> Python packages for creating custom Excel sheets and .pdf reports while iterating the data frames. Everything looks great, and all of the named packages do their job really well.</p>

<p>My concern though is that I feel that my code gets hard to maintain as I need to access the same data frame rows multiple times in multiple calls.</p>

<p>Say I need to get manager names that are responsible for shops which had sales more than 1500 in year 2010. My code is filled with this kind of calls:</p>

<pre><code>managers[managers['ShopId'].isin(sales[sales['Year2010'] &gt; 1500]['ShopId'])]['ManagerName'].values
&gt;&gt;&gt; array(['Rob', 'John'], dtype=object)
</code></pre>

<p>I think it is hard to see what is going on while reading this line of code. I could create multiple intermediate variables, but this would add multiple lines of code.</p>

<p>How common is it to sacrifice database normalization ideology and merge all the pieces into a single data frame to get a more maintainable code? There are obviously cons of having a single data frame as it might get messy when trying to merge other data frames that might be needed later on. Merging them of course leads to data redundancy as the same manager can be assigned to multiple shops.</p>

<pre><code>df = managers.merge(sales,how='left',on='ShopId').merge(shops,how='left',on='ShopId')
print df

   ManagerId ManagerName  ShopId  Year2010  Year2011  Year2012 ShopName
0     112233         Rob      99      2000      3000      4000    Shop1
1     445566        John      88      2500      3500      4500    Shop2
</code></pre>

<p>At least this call gets smaller:</p>

<pre><code>df[df['Year2010'] &gt; 1500]['ManagerName'].values
&gt;&gt;&gt; array(['Rob', 'John'], dtype=object)
</code></pre>

<p>Maybe pandas is a wrong tool for this kind of job? </p>

<p>C# developers at office frown at me and tell me use the classes, but then I will have a bunch of methods like <code>get_manager_sales(managerid)</code> and so forth. Iterating class instances for reporting also sounds troublesome as I would need to implement some sorting and indexing (which I get for free with <code>pandas</code>).</p>

<p>Dictionary would work, but it makes it also difficult to modify existing data, doing merges etc. The syntax doesn't get much better either.</p>

<pre><code>data_dict = df.to_dict('records')
[{'ManagerId': 112233L,
  'ManagerName': 'Rob',
  'ShopId': 99L,
  'ShopName': 'Shop1',
  'Year2010': 2000L,
  'Year2011': 3000L,
  'Year2012': 4000L},
 {'ManagerId': 445566L,
  'ManagerName': 'John',
  'ShopId': 88L,
  'ShopName': 'Shop2',
  'Year2010': 2500L,
  'Year2011': 3500L,
  'Year2012': 4500L}]
</code></pre>

<p>Get manager names that are responsible for shops which had sales more than 1500 in year 2010.</p>

<pre><code>[row['ManagerName'] for row in data_dict if row['Year2010'] &gt; 1500]
&gt;&gt;&gt; ['Rob', 'John']
</code></pre>

<p><strong>In this particular case with the data I operate with, should I go all the way with <code>pandas</code> or is there another way to write cleaner code while taking advantage of the power of <code>pandas</code>?</strong></p>

<p>I would choose Pandas, because it's much faster, has an excellent and extremely rich API, a source code looks much cleaner and better, etc.</p>

<p>BTW the following line can be easily rewritten:</p>

<pre><code>managers[managers['ShopId'].isin(sales[sales['Year2010'] &gt; 1500]['ShopId'])]['ManagerName'].values
</code></pre>

<p>as:</p>

<pre><code>ShopIds = sales.ix[sales['Year2010'] &gt; 1500, 'ShopId']
managers.query('ShopId in @ShopIds')['ManagerName'].values
</code></pre>

<p>IMO it's pretty easy to read and understand</p>

<p>PS you may also want to store your data in a <code>SQL</code>-able database and use SQL or to store it in HDF Store and use <code>where</code> parameter - in both cases you can benefit from indexing "search" columns</p>

python class oop pandas dictionary