将GraphLab SFrame转换为{key: value}字典

5

给定这样的SFrame:

+------+-----------+-----------+-----------+-----------+-----------+-----------+
|  X1  |     X2    |     X3    |     X4    |     X5    |     X6    |     X7    |
+------+-----------+-----------+-----------+-----------+-----------+-----------+
| the  | -0.060292 |  0.06763  | -0.036891 |  0.066684 |  0.024045 |  0.099091 |
|  ,   |  0.026625 |  0.073101 | -0.027073 | -0.019504 |  0.04173  |  0.038811 |
|  .   | -0.005893 |  0.093791 |  0.015333 |  0.046226 |  0.032791 |  0.110069 |
|  of  | -0.050371 |  0.031452 |  0.04091  |  0.033255 | -0.009195 |  0.061086 |
| and  |  0.005456 |  0.063237 | -0.075793 | -0.000819 |  0.003407 |  0.053554 |
|  to  |  0.01347  |  0.043712 | -0.087122 |  0.015258 |  0.08834  |  0.139644 |
|  in  | -0.019466 |  0.077509 | -0.102543 |  0.034337 |  0.130886 |  0.032195 |
|  a   | -0.072288 | -0.017494 | -0.018383 |  0.001857 |  -0.04645 |  0.133424 |
|  is  |  0.052726 |  0.041903 |  0.163781 |  0.006887 |  -0.07533 |  0.108394 |
| for  | -0.004082 | -0.024244 |  0.042166 |  0.007032 | -0.081243 |  0.026162 |
|  on  | -0.023709 | -0.038306 |  -0.16072 | -0.171599 |  0.150983 |  0.042044 |
| that |  0.062037 |  0.100348 | -0.059753 | -0.041444 |  0.041156 |  0.166704 |
|  )   |  0.052312 |  0.072473 |  -0.02067 | -0.015581 |  0.063368 | -0.017216 |
|  (   |  0.051408 |  0.186162 |  0.03028  | -0.048425 |  0.051376 |  0.004989 |
| with |  0.091825 | -0.081649 | -0.087926 | -0.061273 |  0.043528 |  0.107864 |
| was  |  0.046042 | -0.058529 |  0.040581 |  0.067748 |  0.053724 |  0.041067 |
|  as  |  0.025248 | -0.012519 | -0.054685 | -0.040581 |  0.051061 |  0.114956 |
|  it  |  0.028606 |  0.106391 |  0.025065 |  0.023486 |  0.011184 |  0.016715 |
|  by  | -0.096704 |  0.150165 |  -0.01775 |  -0.07178 |  0.004458 |  0.098807 |
|  be  | -0.109489 | -0.025908 |  0.025608 |  0.076263 | -0.047246 |  0.100489 |
+------+-----------+-----------+-----------+-----------+-----------+-----------+

如何将SFrame转换为字典,使得X1列作为键,X2X7作为np.array()

我尝试了逐行迭代原始的SFrame,并执行以下操作:

>>> import graphlab as gl
>>> import numpy as np
>>> x = gl.SFrame()
>>> a = np.array([1,2,3])
>>> w = 'foo'
>>> x.append(gl.SFrame({'word':[w], 'vector':[a]}))
Columns:
    vector  array
    word    str

Rows: 1

Data:
+-----------------+------+
|      vector     | word |
+-----------------+------+
| [1.0, 2.0, 3.0] | foo  |
+-----------------+------+
[1 rows x 2 columns]

还有其他的方法可以做到相同的效果吗?


编辑

在尝试了@papayawarrior的解决方案后,如果我可以将整个数据框加载到内存中,则它可以正常工作,但有一些怪癖使其变得奇怪。

假设我原始输入到SFrame与上面呈现的相同(有501列),但是在.csv文件中,我有代码将它们读入所需的字典:

def get_embeddings(embedding_gzip, size):
    coltypes = [str] + [float] * size
    sf = gl.SFrame.read_csv('compose-vectors/' + embedding_gzip, delimiter='\t', column_type_hints=coltypes, header=False, quote_char='\0')
    sf = sf.pack_columns(['X'+str(i) for i in range(2, size+1)])
    df = sf.to_dataframe().set_index('X1')
    print list(df)
    return df.to_dict(orient='dict')['X2']

但是奇怪的是,它会报错:

  File "sts_compose.py", line 28, in get_embeddings
    return df.to_dict(orient='dict')['X2']
KeyError: 'X2'

在将数据转换成字典之前,当我检查列名时,我发现我的列名不是'X1'和'X2',而是list(df)打印出['X501', 'X3']

我转换GraphLab.SFrame -> pandas.DataFrame -> dict的方法有问题吗?

我知道我可以通过以下方法解决这个问题,但问题仍然存在:“列名为什么会变得如此奇怪?”:

def get_embeddings(embedding_gzip, size):
    coltypes = [str] + [float] * size
    sf = gl.SFrame.read_csv('compose-vectors/' + embedding_gzip, delimiter='\t', column_type_hints=coltypes, header=False, quote_char='\0')
    sf = sf.pack_columns(['X'+str(i) for i in range(2, size+1)])
    df = sf.to_dataframe().set_index('X1')
    col_names = list(df)
    return df.to_dict(orient='dict')[col_names[1]]

关于编辑中的问题,Adrien Renaud的答案使用了SFrame.pack_columns函数中的new_column_name参数,我认为这是一个好主意,可以确保您知道数据列。 - papayawarrior
1
另一个小提示是重命名您的单词列,然后在pack_columns中使用column_prefix参数以避免列表理解。我刚刚更新了我的答案来展示这一点。 - papayawarrior
2个回答

3

还有其他的方法可以做到同样的事情吗? 是的,您可以使用SFrame类的pack_columns方法。

import graphlab as gl
data = gl.SFrame()
data.add_column(gl.SArray(['foo', 'bar']), 'X1')
data.add_column(gl.SArray([1., 3.]), 'X2')
data.add_column(gl.SArray([2., 4.]), 'X3')
print data
+-----+-----+-----+
|  X1 |  X2 |  X3 |
+-----+-----+-----+
| foo | 1.0 | 2.0 |
| bar | 3.0 | 4.0 |
+-----+-----+-----+
[2 rows x 3 columns]

import array
data = data.pack_columns(['X2', 'X3'], dtype=array.array, new_column_name='vector')
data = data.rename({'X1':'word'})
print data
+------+------------+
| word |   vector   |
+------+------------+
| foo  | [1.0, 2.0] |
| bar  | [3.0, 4.0] |
+------+------------+
[2 rows x 2 columns]

b=data['vector'][0]
print type(b)
<type 'array.array'>

如何将SFrame转换为字典,使X1列成为键,X2至X7成为np.array()?

我没有找到任何内置的方法来将SFrame转换为字典。您可以尝试以下方法(可能会非常慢):

a={}
def dump_sframe_to_dict(row, a):
    a[row['word']]=row['vector']
data.apply(lambda x: dump_sframe_to_dict(x, a))
print a
{'foo': array('d', [1.0, 2.0]), 'bar': array('d', [3.0, 4.0])}

简短的问题,当你读取一行数据,比如说 data[0],然后取向量列,data[0][vector],然后执行 type(data[0][vector]),你得到的是一个列表还是一个NumPy数组? - alvas
1
通过执行 data['vector'][0],我得到了一个 array.array 的实例。 - Adrien Renaud

2

已根据帖子中的新问题进行编辑。

@Adrien Renaud关于SFrame.pack_columns方法的建议非常准确,但是如果您的数据集适合内存,我建议在最后一个问题中使用Pandas dataframe to_dict方法。

>>> import graphlab as gl
>>> sf = gl.SFrame({'X1': ['cat', 'dog'], 'X2': [1, 2], 'X3': [3, 4]})
>>> sf
+-----+----+----+
|  X1 | X2 | X3 |
+-----+----+----+
| cat | 1  | 3  |
| dog | 2  | 4  |
+-----+----+----+

>>> sf2 = sf.rename({'X1': 'word'})
>>> sf2 = sf.pack_columns(column_prefix='X', new_column_name='vector')
>>> sf2
+------+--------+
| word | vector |
+------+--------+
| cat  | [1, 3] |
| dog  | [2, 4] |
+------+--------+

>>> df = sf2.to_dataframe().set_index('word')
>>> result = df.to_dict(orient='dict')['vector']
>>> result
{'cat': [1, 3], 'dog': [2, 4]}

谢谢!这非常有帮助。我有一个快速问题,type(array[0][results]) 返回一个列表,我需要将它们显式地转换为 np.array() 以进行向量操作,对吗? - alvas
我不完全确定你所说的 array[0] 是什么意思,但是假设你指的是 result['cat'],那么它将会是一个列表,你需要显式地将其转换为 numpy 数组。 - papayawarrior
是的!再次感谢!将它们转换为numpy数组可以实现我需要的字典。不幸的是,使用Python字典得到结果意味着我必须有足够的RAM来存储整个字典。是否可能将其转换回SFrame或DataFrame,以便graphlab或pandas使用tcmalloc处理大型字典? - alvas
1
你肯定可以重新制作SFrame,但这样做就会偏离最初的目标,即将数据放在字典中。一个建议是在原始的SFrame中进行特征工程,甚至在列被打包之后,然后只将一小部分转换为字典。 - papayawarrior
dict[key]SFrame.filter_by(values=[key], column_name='word') 更快吗?Python 字典是 O(1),因为它是哈希搜索,而另一个则是 O(n),对吗?或者 GraphLab 足够聪明以分片 SFrame 吗? - alvas

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