用pandas和numpy解析冒号分隔的稀疏数据

2 投票
2 回答
855 浏览
提问于 2025-04-18 15:56

我想用pandas或numpy来解析一种数据文件,这种文件的格式是“列索引:值”。比如说:

0:23 3:41 1:31 2:65

这对应的矩阵是:

[[23 0 0 41] [0 31 65 0]]

这种方式在文件中表示稀疏数据似乎很常见,但我找不到一种简单的方法来解析它,而不需要在调用read_csv之后进行某种迭代处理。

2 个回答

1

那么,逐行解析文件是否可行,比如:

from scipy.sparse import coo_matrix

rows, cols, values = [], [], []

with open('sparse.txt') as f:
    for i, line in enumerate(f):
        for cell in line.strip().split(' '):
            col, value = cell.split(':')
            rows.append(i)
            cols.append(int(col))
            values.append(int(value))

matrix = coo_matrix((values, (rows, cols)))

print matrix.todense()

还是说你需要一个更快的一步实现?我不太确定这是否可能。

编辑 #1: 你可以通过使用正则表达式来避免逐行分割的过程,这样可以得到以下替代实现:

import numpy as np
from scipy.sparse import coo_matrix
import re

rows, cols, values = [], [], []

with open('sparse.txt') as f:
    for i, line in enumerate(f):
        numbers = map(int, re.split(':| ', line))
        rows.append([i] * (len(numbers) / 2))
        cols.append(numbers[::2])
        values.append(numbers[1::2])

matrix = coo_matrix((np.array(values).flatten(),
                     (np.array(rows).flatten(),
                      np.array(cols).flatten())))

print matrix.todense()

编辑 #2: 我找到了一种更简短的解决方案,没有显式的循环:

from scipy.sparse import coo_matrix, vstack

def parseLine(line):
    nums = map(int, line.split(' '))
    return coo_matrix((nums[1::2], ([0] * len(nums[0::2]), nums[0::2])), (1, 4))

with open('sparse.txt') as f:
    lines = f.read().replace(':', ' ').split('\n')
    cols = max(map(int, " ".join(lines).split(" "))[::2])
    M = vstack(map(parseLine, lines))

print M.todense()

这个循环隐藏在对 linesmap 命令中。我认为没有完全不使用循环的解决方案,因为大多数内置函数都需要用到循环,而且很多字符串解析的方法,比如 re.finditer 只会返回迭代器。

2

我最近发现,这实际上是svm-light格式的数据集。你可以使用一个叫做svm加载器的工具来读取这样的数据集,具体可以参考这个链接:

http://scikit-learn.org/stable/modules/generated/sklearn.datasets.load_svmlight_file.html

撰写回答