将字典中的列表转换为Series

7

我正在尝试从HTML输入文件中读取行,并准备Series/DataFrames,以便最终创建图形。我使用lxml的objectify将HTML数据行转换为列表。无论何时我尝试将列表数据制作成Series或DataFrame,我得到的Series(或DataFrame)包含的元素数量等于我的列表中的项目数,但元素的数据是我的列表本身。

我可以展示我的问题最简单的方法是:

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)

HTML系列最终看起来会像这样:

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

我正在寻找类似下面的内容:

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               

我做错了什么?我对发生的事情感到困惑。当我尝试将每一列读入列表时:

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

我的列表最终看起来像这样:

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

但出于某些原因:

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

我需要将这些元素转换为普通字符串和整数吗?


确保labdata['192.168.1.0']['Utilization']的类型实际上为list,例如将其放在list()中。它可能类似于列表但实际上不是列表,还要显示系列的第一个元素的类型,例如type(s[0]) - Jeff
为什么这个问题被踩了?该问题很容易理解并提供了一个可工作的SSCCE,这已经让它排名相当高了。唯一缺少的是对期望输出的描述,但在上下文中我认为它已经很清楚了。 - DSM
2
@dooz:作为一种解决方法,您可以使用Series(htmldata中的obj.pyval)。我不能立即看出原因,但是lxml.objectify.*Element对象的某些特性与Series构造不兼容。 - DSM
没错,我的(现在已删除的)回答基本上就是DSM的评论。 - Dan Allan
2个回答

7
问题在于htmldata中的元素不是简单类型,而np.isscalar在这里被愚弄了(因为它确定我们是否有列表或标量的方式 只需将元素字符串化,这样就可以解决问题了。
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               

啊,+1。我还记得isscalar在Sage中也会出现问题——numpy不认识Sage整数作为标量,所以数组的索引不太对。我认为我更喜欢pyval方法,因为它保留了更多的类型信息。 - DSM
同意……我认为Pandas不太可能做其他事情,因为要确定用户是否真的将列表作为系列元素传递并且是有意为之,这相当耗费资源。 - Jeff

2

好问题!这是奇怪的行为。

问题发生的原因是您正在向 Series 传递一个包含 lxml.objectify.StringElement 的列表。 pandas 是由np.array支持的,因此它更喜欢将其数据存储在一致的数组中。它因此将所有内容抽象成 np.object,以便可以将它们塞入数组中。确实,如果您查看数据的基础数组 (Series.values),则会发现已经创建了该数组,尽管它是一个由lxml.objectify.StringElements组成的 numpy 数组,这可能不是您想要的。

当然,简单的解决方法是将所有内容转换为字符串,这在这种情况下可能是您想要的。


但是您会问为什么会打印出有趣的结果呢? 如果您深入研究 pandas 中的代码,最终会到达 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

换句话说,Pandas 发现 lxml 对象不是基本字符串,因此假定它们是序列。Pandas 应该检查 isinstance(x, collections.Sequence)...

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接