将唯一列转换为具有相应值的 SFrame headers
Converting a unique columns into SFrame headers with corresponding values
我有一个 tab-separated 文件:
$ echo -e 'abc\txyz\t0.9\nefg\txyz\t0.3\nlmn\topq\t0.23\nabc\tjkl\t0.5\n' > test.txt
$ cat test.txt
abc xyz 0.9
efg xyz 0.3
lmn opq 0.23
abc jkl 0.5
$ python
>>> from sframe import SFrame
>>> sf = SFrame.read_csv('test.txt', header=False, delimiter='\t', column_type_hints=[unicode, unicode, float])
[INFO] sframe.cython.cy_server: SFrame v2.1 started. Logging /tmp/sframe_server_1479718846.log
>>> sf
Columns:
X1 str
X2 str
X3 float
Rows: 4
Data:
+-----+-----+------+
| X1 | X2 | X3 |
+-----+-----+------+
| abc | xyz | 0.9 |
| efg | xyz | 0.3 |
| lmn | opq | 0.23 |
| abc | jkl | 0.5 |
+-----+-----+------+
[4 rows x 3 columns]
目标是实现一个不同的 SFrame,其中将有一个由 'X1' 组成的唯一行,列是来自 'X2' 的值,即:
+-----+-----+-----+------+
| X1 | xyz | opq | jkl |
+-----+-----+-----+------+
| abc | 0.9 | 0.0 | 0.5 |
+-----+-----+-----+------+
| efg | 0.3 | 0.0 | 0.0 |
+-----+-----+-----+------+
| lmn | 0.0 | 0.23| 0.0 |
+-----+-----+-----+------+
我试过不使用 SFrame:
>>> import io
>>> with io.open('test.txt', 'r', encoding='utf8') as fin:
... for line in fin:
... if line.strip():
... s,t,p = line.strip().split('\t')
... matrix[(s,t)] = float(p)
...
>>> matrix
{(u'abc', u'jkl'): 0.5, (u'abc', u'xyz'): 0.9, (u'lmn', u'opq'): 0.23, (u'efg', u'xyz'): 0.3}
>>> col1, col2 = zip(*matrix.keys())
>>> [[matrix.get((c1,c2), 0.0) for c2 in col2] for c1 in col1]
[[0.5, 0.9, 0.0, 0.9], [0.5, 0.9, 0.0, 0.9], [0.0, 0.0, 0.23, 0.0], [0.0, 0.3, 0.0, 0.3]]
>>> import numpy as np
>>> np.array([[matrix.get((c1,c2), 0.0) for c2 in col2] for c1 in col1])
array([[ 0.5 , 0.9 , 0. , 0.9 ],
[ 0.5 , 0.9 , 0. , 0.9 ],
[ 0. , 0. , 0.23, 0. ],
[ 0. , 0.3 , 0. , 0.3 ]])
>>> SFrame(np.array([[matrix.get((c1,c2), 0.0) for c2 in col2] for c1 in col1]))
Columns:
X1 array
Rows: 4
Data:
+-----------------------+
| X1 |
+-----------------------+
| [0.5, 0.9, 0.0, 0.9] |
| [0.5, 0.9, 0.0, 0.9] |
| [0.0, 0.0, 0.23, 0.0] |
| [0.0, 0.3, 0.0, 0.3] |
+-----------------------+
[4 rows x 1 columns]
但这仍然没有给我想要的 SFrame。 我应该如何将唯一列转换为具有相应值的 SFrame headers? 即实现:
+-----+-----+-----+------+
| X1 | xyz | opq | jkl |
+-----+-----+-----+------+
| abc | 0.9 | 0.0 | 0.5 |
+-----+-----+-----+------+
| efg | 0.3 | 0.0 | 0.0 |
+-----+-----+-----+------+
| lmn | 0.0 | 0.23| 0.0 |
+-----+-----+-----+------+
一定有更简单的方法来做到这一点。想象一下,唯一的没有。列元素的数量最多可达 1,000,000,生成的 SFrame 的大小可能为 1,000,000 X 1,000,000,因此需要 SFrame 或 HDF 之类的数据结构,而不是 numpy 数组或本机 python 列表列表。
你想做的事情在 pandas 中真的很微不足道,使用 df.pivot(index='X1', columns='X2', values='X3')
或 df.set_index(['X1','X2']).unstack('X2')
(见文末 post)。
似乎SFrame中都不存在。 (我可能是错的,直到现在才使用过 SFrame 但我在文档中找不到任何证据)。
您需要使用 SFrame.unstack() and SFrame.unpack() 才能达到预期的效果。
from sframe import SFrame
sf = SFrame.read_csv('test.txt', header=False, delimiter='\t', column_type_hints=[unicode, unicode, float])
拳头,展开:
sf2 = sf.unstack(['X2', 'X3'], new_column_name='dict_counts')
sf2
X1 dict_counts
efg {'xyz': 0.3}
lmn {'opq': 0.23}
abc {'jkl': 0.5, 'xyz': 0.9}
然后解压:
out = sf2.unpack('dict_counts', column_name_prefix='')
out
X1 jkl opq xyz
efg None None 0.3
lmn None 0.23 None
abc 0.5 None 0.9
最后,如果您愿意,可以填写 na 以将 None
替换为 0
:
for c in out.column_names():
out = out.fillna(c, 0)
out
X1 jkl opq xyz
efg 0.0 0.0 0.3
lmn 0.0 0.23 0.0
abc 0.5 0.0 0.9
另一种粗略的方法可能是将其转换为 pandas DataFrame 以便对其进行透视,但如果您的数据集太大,这可能不起作用:
import pandas as pd
from sframe import SFrame
sf = SFrame.read_csv('test.txt', header=False, delimiter='\t', column_type_hints=[unicode, unicode, float])
sf = SFrame(data=sf.to_dataframe().pivot(index='X1', columns='X2', values='X3').fillna(0).reset_index())
我有一个 tab-separated 文件:
$ echo -e 'abc\txyz\t0.9\nefg\txyz\t0.3\nlmn\topq\t0.23\nabc\tjkl\t0.5\n' > test.txt
$ cat test.txt
abc xyz 0.9
efg xyz 0.3
lmn opq 0.23
abc jkl 0.5
$ python
>>> from sframe import SFrame
>>> sf = SFrame.read_csv('test.txt', header=False, delimiter='\t', column_type_hints=[unicode, unicode, float])
[INFO] sframe.cython.cy_server: SFrame v2.1 started. Logging /tmp/sframe_server_1479718846.log
>>> sf
Columns:
X1 str
X2 str
X3 float
Rows: 4
Data:
+-----+-----+------+
| X1 | X2 | X3 |
+-----+-----+------+
| abc | xyz | 0.9 |
| efg | xyz | 0.3 |
| lmn | opq | 0.23 |
| abc | jkl | 0.5 |
+-----+-----+------+
[4 rows x 3 columns]
目标是实现一个不同的 SFrame,其中将有一个由 'X1' 组成的唯一行,列是来自 'X2' 的值,即:
+-----+-----+-----+------+
| X1 | xyz | opq | jkl |
+-----+-----+-----+------+
| abc | 0.9 | 0.0 | 0.5 |
+-----+-----+-----+------+
| efg | 0.3 | 0.0 | 0.0 |
+-----+-----+-----+------+
| lmn | 0.0 | 0.23| 0.0 |
+-----+-----+-----+------+
我试过不使用 SFrame:
>>> import io
>>> with io.open('test.txt', 'r', encoding='utf8') as fin:
... for line in fin:
... if line.strip():
... s,t,p = line.strip().split('\t')
... matrix[(s,t)] = float(p)
...
>>> matrix
{(u'abc', u'jkl'): 0.5, (u'abc', u'xyz'): 0.9, (u'lmn', u'opq'): 0.23, (u'efg', u'xyz'): 0.3}
>>> col1, col2 = zip(*matrix.keys())
>>> [[matrix.get((c1,c2), 0.0) for c2 in col2] for c1 in col1]
[[0.5, 0.9, 0.0, 0.9], [0.5, 0.9, 0.0, 0.9], [0.0, 0.0, 0.23, 0.0], [0.0, 0.3, 0.0, 0.3]]
>>> import numpy as np
>>> np.array([[matrix.get((c1,c2), 0.0) for c2 in col2] for c1 in col1])
array([[ 0.5 , 0.9 , 0. , 0.9 ],
[ 0.5 , 0.9 , 0. , 0.9 ],
[ 0. , 0. , 0.23, 0. ],
[ 0. , 0.3 , 0. , 0.3 ]])
>>> SFrame(np.array([[matrix.get((c1,c2), 0.0) for c2 in col2] for c1 in col1]))
Columns:
X1 array
Rows: 4
Data:
+-----------------------+
| X1 |
+-----------------------+
| [0.5, 0.9, 0.0, 0.9] |
| [0.5, 0.9, 0.0, 0.9] |
| [0.0, 0.0, 0.23, 0.0] |
| [0.0, 0.3, 0.0, 0.3] |
+-----------------------+
[4 rows x 1 columns]
但这仍然没有给我想要的 SFrame。 我应该如何将唯一列转换为具有相应值的 SFrame headers? 即实现:
+-----+-----+-----+------+
| X1 | xyz | opq | jkl |
+-----+-----+-----+------+
| abc | 0.9 | 0.0 | 0.5 |
+-----+-----+-----+------+
| efg | 0.3 | 0.0 | 0.0 |
+-----+-----+-----+------+
| lmn | 0.0 | 0.23| 0.0 |
+-----+-----+-----+------+
一定有更简单的方法来做到这一点。想象一下,唯一的没有。列元素的数量最多可达 1,000,000,生成的 SFrame 的大小可能为 1,000,000 X 1,000,000,因此需要 SFrame 或 HDF 之类的数据结构,而不是 numpy 数组或本机 python 列表列表。
你想做的事情在 pandas 中真的很微不足道,使用 df.pivot(index='X1', columns='X2', values='X3')
或 df.set_index(['X1','X2']).unstack('X2')
(见文末 post)。
似乎SFrame中都不存在。 (我可能是错的,直到现在才使用过 SFrame 但我在文档中找不到任何证据)。
您需要使用 SFrame.unstack() and SFrame.unpack() 才能达到预期的效果。
from sframe import SFrame
sf = SFrame.read_csv('test.txt', header=False, delimiter='\t', column_type_hints=[unicode, unicode, float])
拳头,展开:
sf2 = sf.unstack(['X2', 'X3'], new_column_name='dict_counts')
sf2
X1 dict_counts
efg {'xyz': 0.3}
lmn {'opq': 0.23}
abc {'jkl': 0.5, 'xyz': 0.9}
然后解压:
out = sf2.unpack('dict_counts', column_name_prefix='')
out
X1 jkl opq xyz
efg None None 0.3
lmn None 0.23 None
abc 0.5 None 0.9
最后,如果您愿意,可以填写 na 以将 None
替换为 0
:
for c in out.column_names():
out = out.fillna(c, 0)
out
X1 jkl opq xyz
efg 0.0 0.0 0.3
lmn 0.0 0.23 0.0
abc 0.5 0.0 0.9
另一种粗略的方法可能是将其转换为 pandas DataFrame 以便对其进行透视,但如果您的数据集太大,这可能不起作用:
import pandas as pd
from sframe import SFrame
sf = SFrame.read_csv('test.txt', header=False, delimiter='\t', column_type_hints=[unicode, unicode, float])
sf = SFrame(data=sf.to_dataframe().pivot(index='X1', columns='X2', values='X3').fillna(0).reset_index())