2013-04-04 12 views
7

Mam nadzieję, że wykorzystam pandy jako główny obiekt śledzenia (seria punktów w przestrzeni parametru z MCMC).Przechowywanie tablic wielowymiarowych w pandach Kolumny DataFrame

Mam listę dykt ciągów-> tablic, które chciałbym przechowywać w pandach. Klucze w dyktach są zawsze takie same, a dla każdego klawisza kształt tablicy numpy jest zawsze taki sam, ale kształt może być różny dla różnych kluczy i może mieć inną liczbę wymiarów.

Używałem , który wydaje się działać dobrze dla wartości 1d, ale dla wartości nd> 1 pandy przechowuje wartości jako obiekty, które nie pozwalają na ładne kreślenie i inne fajne rzeczy. Wszelkie sugestie, jak uzyskać lepsze zachowanie?

dane Przykładowe

point = {'x': array(-0.47652306228698005), 
     'y': array([[-0.41809043], 
        [ 0.48407823]])} 

points = 10 * [ point] 

Chciałbym móc zrobić coś takiego

df = DataFrame(points) 

lub

df = DataFrame() 
df.append(points, ignore_index=True) 

i mają

>> df['x'][1].shape 
() 
>> df['y'][1].shape 
(2,1) 
+1

Czy zapoznałeś się z [panelem] (http://pandas.pydata.org/pandas-docs/dev/dsintro.html#panel) datastructure? Nie jestem pewien, czy to pomaga w przypadku użycia ... –

+1

Czy możemy uzyskać próbki danych dla Twojego problemu? – BKay

+0

Z pewnością dodałem trochę wyżej. To pomaga? A może chcesz coś więcej? –

Odpowiedz

3

Jest to trochę sprzeczne z filozofią Pandasa, która wydaje się postrzegać Series jako jednowymiarową strukturę danych. Dlatego musisz ręcznie utworzyć Series, aby poinformować ich, że mają typ danych: "object". Oznacza to, że nie stosuje żadnych automatycznych konwersji danych.

Można to zrobić tak (kolejność sesji ipython):

In [9]: import pandas as pd 

In [1]: point = {'x': array(-0.47652306228698005), 
    ...:   'y': array([[-0.41809043], 
    ...:      [ 0.48407823]])} 

In [2]: points = 10 * [ point] 

In [5]: lx = [p["x"] for p in points] 

In [7]: ly = [p["y"] for p in points] 

In [40]: sx = pd.Series(lx, dtype=numpy.dtype("object")) 

In [38]: sy = pd.Series(ly, dtype=numpy.dtype("object")) 

In [43]: df = pd.DataFrame({"x":sx, "y":sy}) 

In [45]: df['x'][1].shape 
Out[45]:() 

In [46]: df['y'][1].shape 
Out[46]: (2, 1) 
+1

Dobrze wiedzieć, że to jest panda. Myślę, że metoda df.append (points) zrobi to w zasadzie. –

+0

@JohnSalvatier ma rację! – hobs

7

Stosunkowo nowa biblioteka xray [1] ma Dataset i DataArray struktur, które robią dokładnie to, o co prosisz.

Tu jest moje zdanie na temat problemu, napisany jako ipython sesji:

>>> import numpy as np 
>>> import xray 

>>> ## Prepare data: 
>>> # 
>>> point = {'x': np.array(-0.47652306228698005), 
...   'y': np.array([[-0.41809043], 
...      [ 0.48407823]])} 
>>> points = 10 * [point] 

>>> ## Convert to Xray DataArrays: 
>>> # 
>>> list_x = [p['x'] for p in points] 
>>> list_y = [p['y'] for p in points] 
>>> da_x = xray.DataArray(list_x, [('x', range(len(list_x)))]) 
>>> da_y = xray.DataArray(list_y, [ 
...  ('x', range(len(list_y))), 
...  ('y0', range(2)), 
...  ('y1', [0]), 
... ]) 

Są to dwa DataArray przypadki my zbudowane tak daleko:

>>> print(da_x) 
<xray.DataArray (x: 10)> 
array([-0.47652306, -0.47652306, -0.47652306, -0.47652306, -0.47652306, 
     -0.47652306, -0.47652306, -0.47652306, -0.47652306, -0.47652306]) 
Coordinates: 
    * x  (x) int32 0 1 2 3 4 5 6 7 8 9 


>>> print(da_y.T) ## Transposed, to save lines. 
<xray.DataArray (y1: 1, y0: 2, x: 10)> 
array([[[-0.41809043, -0.41809043, -0.41809043, -0.41809043, -0.41809043, 
     -0.41809043, -0.41809043, -0.41809043, -0.41809043, -0.41809043], 
     [ 0.48407823, 0.48407823, 0.48407823, 0.48407823, 0.48407823, 
      0.48407823, 0.48407823, 0.48407823, 0.48407823, 0.48407823]]]) 
Coordinates: 
    * x  (x) int32 0 1 2 3 4 5 6 7 8 9 
    * y0  (y0) int32 0 1 
    * y1  (y1) int32 0 

Możemy teraz Merge te dwa DataArray w ich wspólnym wymiarze x do jednego wymiaru: DataSet:

I wreszcie możemy przejść, a dane zagregowane sposób Poszukiwany

>>> ds['X'].sum() 
<xray.DataArray 'X'()> 
array(-4.765230622869801) 


>>> ds['Y'].sum() 
<xray.DataArray 'Y'()> 
array(0.659878) 


>>> ds['Y'].sum(axis=1) 
<xray.DataArray 'Y' (x: 10, y1: 1)> 
array([[ 0.0659878], 
     [ 0.0659878], 
     [ 0.0659878], 
     [ 0.0659878], 
     [ 0.0659878], 
     [ 0.0659878], 
     [ 0.0659878], 
     [ 0.0659878], 
     [ 0.0659878], 
     [ 0.0659878]]) 
Coordinates: 
    * x  (x) int32 0 1 2 3 4 5 6 7 8 9 
    * y1  (y1) int32 0 

>>> np.all(ds['Y'].sum(axis=1) == ds['Y'].sum(dim='y0')) 
True 

>>>> ds['X'].sum(dim='y0') 
Traceback (most recent call last): 
ValueError: 'y0' not found in array dimensions ('x',) 

[1] biblioteka do obsługi danych n-wymiarowej z etykietami, jak pandy czy 2D: http://xray.readthedocs.org/en/stable/data-structures.html#dataset

2

łącząc @ Eike na answer i @ komentarzu JohnSalvatier wydaje się dość Pandasonic:

>>> import pandas as pd 
>>> np = pandas.np 
>>> point = {'x': np.array(-0.47652306228698005), 
... ...:   'y': np.array([[-0.41809043], 
... ...:      [ 0.48407823]])} 
>>> points = 10 * [ point] 
>>> df = pd.DataFrame().append(points) 
>>> df.x 
# 0 -0.476523062287 
# ... 
# 9 -0.476523062287 
# Name: x, dtype: object 
>>> df.y 
# 0 [[-0.41809043], [0.48407823]] 
# ... 
# 9 [[-0.41809043], [0.48407823]] 
# Name: y, dtype: object 
>>> df.y[0] 
# array([[-0.41809043], 
#  [ 0.48407823]]) 
>>> df.y[0].shape 
# (2, 1) 

Aby wykreślić (i robić wszystkie inne fajne rzeczy, 2-D pandy) trzeba jeszcze ręcznie konwertować kolumnę tablic z powrotem do DataFrame:

>>> dfy = pd.DataFrame([row.T[0] for row in df2.y]) 
>>> dfy += np.matrix([[0] * 10, range(10)]).T 
>>> dfy *= np.matrix([range(10), range(10)]).T 
>>> dfy.plot() 

example 2-D plot

przechowywanie tego na dysku, użyj to_pickle:

>>> df.to_pickle('/tmp/sotest.pickle') 
>>> df2 = pd.read_pickle('/tmp/sotest.pickle') 
>>> df.y[0].shape 
# (2, 1) 

Jeśli używasz to_csv Twojego np.array s przedmioty stają się ciągi:

>>> df.to_csv('/tmp/sotest.csv') 
>>> df2 = pd.DataFrame.from_csv('/tmp/sotest.csv') 
>>> df2.y[0] 
# '[[-0.41809043]\n [ 0.48407823]]' 
Powiązane problemy