2013-04-02 19 views
7

Sto provando a leggere le righe da un file di input HTML e preparare Serie/DataFrames in modo da poter creare grafici. Sto usando l'oggettivazione di lxml per prendere linee di dati HTML e convertirli in una lista. Ogni volta che provo a prendere i dati dell'elenco e creare una serie o DataFrame, ottengo una serie (o DataFrame) contenente un numero di elementi uguale al numero di elementi nella mia lista, ma i dati per gli elementi sono la mia lista stessa.Conversione di un elenco in un dett ad una serie

Il modo più semplice che posso mostrare il mio problema è:

from lxml import etree 
from lxml import objectify 
from pandas import Series 
line='<tr class="alt"><td>192.168.1.0</td><td>XXDHCP</td><td>Y</td><td>255</td><td>0</td><td>YYDHCP</td><td>Y</td><td>250</td><td>0</td><td>0%</td><td>505</td><td>505</td><td>0</td><td></td></tr>' 
htmldata=(objectify.fromstring(line)).getchildren() 
htmlseries=Series(htmldata) 

htmlseries finisce per assomigliare:

0  [[[192.168.1.0, XXDHCP, Y, 255, 0, YYDHCP, Y, ... 
1  [[[192.168.1.0, XXDHCP, Y, 255, 0, YYDHCP, Y, ... 
2  [[[192.168.1.0, XXDHCP, Y, 255, 0, YYDHCP, Y, ... 
3  [[[192.168.1.0, XXDHCP, Y, 255, 0, YYDHCP, Y, ... 
4  [[[192.168.1.0, XXDHCP, Y, 255, 0, YYDHCP, Y, ... 
5  [[[192.168.1.0, XXDHCP, Y, 255, 0, YYDHCP, Y, ... 
6  [[[192.168.1.0, XXDHCP, Y, 255, 0, YYDHCP, Y, ... 
7  [[[192.168.1.0, XXDHCP, Y, 255, 0, YYDHCP, Y, ... 
8  [[[192.168.1.0, XXDHCP, Y, 255, 0, YYDHCP, Y, ... 
9  [[[192.168.1.0, XXDHCP, Y, 255, 0, YYDHCP, Y, ... 
10 [[[192.168.1.0, XXDHCP, Y, 255, 0, YYDHCP, Y, ... 
11 [[[192.168.1.0, XXDHCP, Y, 255, 0, YYDHCP, Y, ... 
12 [[[192.168.1.0, XXDHCP, Y, 255, 0, YYDHCP, Y, ... 
13 [[[192.168.1.0, XXDHCP, Y, 255, 0, YYDHCP, Y, ... 

type(htmldata[0]) è: lxml.objectify.StringElement
type(htmldata[3]) è: lxml.objectify.IntElement

Mentre io Sto cercando qualcosa come:

0  192.168.1.0 
1   XXDHCP 
2    Y 
3    255 
4    0 
5   YYDHCP 
6    Y 
7    250 
8    0 
9    0% 
10   505 
11   505 
12    0 
13    

Cosa sto sbagliando? Sono un po 'confuso su cosa sta succedendo. Quando provo a leggere ogni colonna in un elenco:

data=objectify.fromstring(line).getchildren() 
labdata[ip]['Scope'].append(data[0]) 
labdata[ip]['Cluster1'].append(data[1]) 
labdata[ip]['Active1'].append(data[2]) 
...etc... 

Mia lista finisce per assomigliare:

labdata['192.168.1.0']['Utilization'] 
['100%', 
'96%', 
'96%', 
'90%', 
'81%', 
'96%', 
'90%', 
'97%', 
'98%', 
'92%', 
'99%', 
...etc... 
] 

Ma per qualche motivo:

Series(labdata['192.168.1.0']['Utilization']) 
0  [[[192.168.1.0, XXDHCP, Y, 0, 383, YYDHCP, Y... 
1  [[[192.168.1.0, XXDHCP, Y, 28, 355, YYDHCP, ... 
2  [[[192.168.1.0, XXDHCP, Y, 28, 355, YYDHCP, ... 
3  [[[192.168.1.0, XXDHCP, Y, 76, 307, YYDHCP, ... 
4  [[[192.168.1.0, XXDHCP, Y, 104, 279, YYDHCP,... 
5  [[[192.168.1.0, XXDHCP, Y, 27, 356, YYDHCP, ... 
6  [[[192.168.1.0, XXDHCP, Y, 66, 317, YYDHCP, ... 
7  [[[192.168.1.0, XXDHCP, Y, 15, 368, YYDHCP, ... 
8  [[[192.168.1.0, XXDHCP, Y, 15, 368, YYDHCP, ... 
9  [[[192.168.1.0, XXDHCP, Y, 54, 329, YYDHCP, ... 
...etc... 

type(labdata['192.168.1.0']['Utilization'][0]) è lxml.objectify.StringElement

Devo lanciare questi elementi su normali stringhe e stringhe?

+0

assicurarsi che il tipo di '' labdata ['192.168.1.0'] ['Utilization'] '' sia in realtà un '' elenco'', ad es. metti '' list() '' attorno ad esso, potrebbe essere list-like ma non in realtà una lista, mostra anche il tipo del primo elemento della serie, ad es. '' type (s [0]) '' – Jeff

+0

Perché è stato downvoted? La domanda è comprensibile e fornisce un SSCCE funzionante, che lo classifica già molto bene. L'unica cosa che manca è una descrizione dell'output desiderato, ma nel contesto penso sia abbastanza chiaro. – DSM

+2

@dooz: come soluzione alternativa puoi usare 'Serie (obj.pyval per obj in htmldata)'. Non riesco a vedere immediatamente perché, ma qualcosa sugli oggetti 'lxml.objectify. * Element' non sta giocando bene con la costruzione di serie. – DSM

risposta

7

Il problema è gli elementi in HTMLData sono tipi non semplici, e si lascia ingannare np.isscalar qui (come questo è come la sua determinazione se abbiamo degli elenchi di liste o una lista di scalari solo stringa i gli elementi sono questo funzionerà

In [23]: print [ type(x) for x in htmldata ] 
[<type 'lxml.objectify.StringElement'>, <type 'lxml.objectify.StringElement'>, <type 'lxml.objectify.StringElement'>, <type 'lxml.objectify.IntElement'>, <type 'lxml.objectify.IntElement'>, <type 'lxml.objectify.StringElement'>, <type 'lxml.objectify.StringElement'>, <type 'lxml.objectify.IntElement'>, <type 'lxml.objectify.IntElement'>, <type 'lxml.objectify.StringElement'>, <type 'lxml.objectify.IntElement'>, <type 'lxml.objectify.IntElement'>, <type 'lxml.objectify.IntElement'>, <type 'lxml.objectify.StringElement'>] 

In [24]: Series([ str(x) for x in htmldata ]) 
Out[24]: 
0  192.168.1.0 
1   XXDHCP 
2    Y 
3    255 
4    0 
5   YYDHCP 
6    Y 
7    250 
8    0 
9    0% 
10   505 
11   505 
12    0 
13    
+0

Ah, +1. Ricordo 'isscalar' che causa problemi anche con Sage -' numpy' non riconosce gli interi Sage come scalari, quindi l'indicizzazione degli array non funziona correttamente. Penso che preferisco l'approccio 'pyval' anche se conserva più informazioni sul tipo. – DSM

+0

d'accordo .... non molto altro penso che possa fare su panda fine perché abbastanza intensivo per determinare se l'utente REALMENTE sta passando una lista come elemento di serie e significa che – Jeff

2

Nizza domanda! questo è un comportamento strano.

Il problema si verifica perché si sta passando Serie una lista lxml.objectify.StringElement s. pandas è sostenuta da np.array s e preferisce quindi avere i propri dati memorizzati in matrici uniformi. Pertanto, tutto si trasforma in un np.object in modo che possa inserirli in un array. Infatti, se guardi l'array sottostante (Series.values) dei tuoi dati, vedrai che è stato creato bene, sebbene si tratti di una serie numerica di lxml.objectify.StringElements che probabilmente non è ciò che desideri.

La soluzione semplice è ovviamente quella di trasmettere tutto a una stringa, che probabilmente è ciò che si vuole fare in questo caso.


Ma perché è divertente stampare, chiedi?Beh, se si esegue il drill attraverso il codice a panda, si finisce al seguente funzione nel pandas.core.common:

def _is_sequence(x): 
    try: 
     iter(x) 
     len(x) # it has a length 
     return not isinstance(x, basestring) and True 
    except Exception: 
     return False 

In altre parole, i panda vede che gli oggetti non sono lxml basestrings, e quindi si assume che sono sequenze. Panda dovrebbe probabilmente controllare isinstance(x, collections.Sequence) ...

+0

è una buona idea! – Jeff

Problemi correlati