Support for tables with unlimited columns in HDF
I wrote a small class that will allow users to utilize HDF tables with significantly more columns than the ~2000 limit currently imposed. I work with mass spec data, and have matrices of ~20,000 x 20,000 x sample_number to deal with so I need things to be written on disk, and compressed.

I'm asking if this is something that would be appreciated to be cleaned up and put in as a PR. It's currently just addressing my needs as they arise, but I could extend and optimize it if there's interest. Alternatively, if I'm reinventing a wheel that already exists in pandas, I'd love to know that as well.

Here's the code for the interested

``` python
class WideTable(object):
    """
    Breaks up a massive table into individual chunks and stores these chunks as separate tables.
    Extends the select and append method to be pandas-like and handle this indexing to mimic a single
    DataFrame
    """
    def __init__(self, store, chunk_size=None, min_itemsize=255):
        self.store = store
        self.index_name = '_store_index'
        self.chunk_size_name = '_chunk_size'
        self.index_itemsize = min_itemsize
        try:
            self.store_index = self.store.select(self.index_name)
        except KeyError:
            self.store_index = pd.DataFrame(columns=['chunk'])
            self.store.put(self.index_name, self.store_index)
        finally:
            self.tables = [i[0] for i in self.store.iteritems()]
        try:
            # stored as a series
            self.chunk_size = self.store.select(self.chunk_size_name)
        except KeyError:
            self.chunk_size = pd.Series(chunk_size if chunk_size is not None else 100)
            self.store.append(self.chunk_size_name, self.chunk_size)
        self.chunk_size = self.chunk_size[0]

    def get_chunk_name(self, name, chunk):
        return '_{0}_{1}'.format(name, chunk)

    def append(self, name, data, column=0):
        # get the existing chunks from the data and insert them to those blocks
        chunks = self.store_index['chunk']
        existing_map = chunks[data.columns]
        new = existing_map[existing_map.isnull()] # Series of new columns
        existing = existing_map.dropna().to_dict() # dict of {'column': 'chunk'}, we want {'chunk': columns set}
        existing_rev = {}
        for key, value in existing.iteritems():
            try:
                existing_rev[value].append(key)
            except KeyError:
                existing_rev[value] = [key]

        # update existing entries
        columns_added = []
        for chunk_index, chunk_columns in existing_rev.iteritems():
            print self.get_chunk_name(name, chunk_index), chunk_columns
            self.store.append(self.get_chunk_name(name, chunk_index), data.loc[:,chunk_columns])
            columns_added.extend(chunk_columns)

        new_cols = list(set(data.columns)-set(columns_added))
        if new_cols:
            data2 = data[new_cols]
            current_chunk = chunks.astype('int').max()
            if pd.isnull(current_chunk):
                current_chunk = 0
            space_taken = len(chunks.where(chunks == str(current_chunk)).dropna())
            if space_taken >= self.chunk_size:
                current_chunk += 1
                end = self.chunk_size
            else:
                end = self.chunk_size-space_taken
            if end > len(new_cols):
                end = len(new_cols)
            start = 0
            while start < len(new_cols):
                chunk_name = self.get_chunk_name(name, current_chunk)
                td = data2.iloc[:,start:end]
                self.store.append(chunk_name, td)
                for col_name in td.columns:
                    self.store_index.loc[col_name,'chunk'] = str(current_chunk)
                self.tables.append(chunk_name)
                start = end
                end += self.chunk_size
                if end > len(new_cols):
                    end = len(new_cols)
                current_chunk += 1
            self.store.put(self.index_name, self.store_index)

    def get_matching_tables(self, name):
        return [i for i in self.tables if i.startswith('/_{0}_'.format(name))]

    def select(self, name, **kwargs):
        t = pd.DataFrame()
        for i in self.get_matching_tables(name):
            values = self.store.select(i,**kwargs)
            if values.empty:
                continue
            t = t.join(values, how='outer')
        return t
```

Basic usage:

``` python
import pandas as pd
import numpy as np
# chunk size is how many columns you want per sub-table and is only required for new tables
wt = WideTable(pd.HDFStore('wide_table.h5', complevel=9, complib='blosc'), chunk_size=3)
df = pd.DataFrame(np.random.randn(8, 10), index=range(8), columns=[chr(i) for i in xrange(70,70+10)])
wt.append('test_table', df)

# show that chunk size is optional
wt = WideTable(pd.HDFStore('wide_table.h5', complevel=9, complib='blosc'))
print wt.chunk_size
# select data
print wt.select('test_table', where='columns==J')
# across tables
print wt.select('test_table', where='columns==[N,I,H]')
print wt.select('test_table', where='columns==[F,J,O]')

```
