将三列表转换为表的脚本

0 投票
6 回答
889 浏览
提问于 2025-04-16 06:14

我有一组数据(CSV文件),格式是三列的:

A, B, C
3277,4733,54.1 
3278,4741,51.0 
3278,4750,28.4 
3278,4768,36.0 
3278,4776,50.1 
3278,4784,51.4 
3279,4792,82.6 
3279,4806,78.2 
3279,4814,36.4 

我需要得到一个三维的列联表,像这样:(抱歉,这个看起来不太好)

A /B     4733      4741      4750      4768      4776      4784      4792      4806      4814
3277   C 54.1                                                
3278                 51      28.4        36      50.1      51.4                  
3279                                                                 82.6      78.2      36.4

这有点像Excel的“透视表”,OpenOffice的数据透视表,或者R语言中的“table(x,y,z)”

问题是我的数据集非常庞大(总共有超过50万行,A和B中大约有400个不同的因素)。由于OpenOffice、Microsoft Office和R的限制,我无法做到这一点。

我相信可以用Python脚本来创建这样的表格。A和B都是数字(但可以当作字符串处理)。

有没有人处理过这个? (伪代码或者C、Java的代码也欢迎……不过我更喜欢Python,因为实现起来更快 :)

编辑: 几乎完成了,多亏了John Machin。以下的Python脚本几乎提供了我想要的结果,但是在写输出文件时,我发现我写的“标题”中的值(取自第一行)与其他行不对应。

from collections import defaultdict as dd
d = dd(lambda: dd(float))

input =  open("input.txt")
output = open("output.txt","w")
while 1:
    line = input.readline()
    if not line:
        break
    line = line.strip('\n').strip('\r')
    splitLine = line.split(',')
    if (len(splitLine) <3):
        break
    d[splitLine[0]][splitLine[1]] = splitLine[2]

output.write("\t")
for k,v in d.items()[0][1].items():
    output.write(str(k)+"\t")
output.write("\n")
for k,v in d.items():
    output.write(k+"\t")
    for k2,v2 in v.items():
        output.write(str(v2)+"\t")
    output.write("\n")

6 个回答

1

在R语言中,我可以这样做:

N <- 1000000
x <- sample(1:400,N,TRUE)
y <- sample(1:400,N,TRUE)
z <- sample(1:400,N,TRUE)

w <- table(x,y,z)

而且内存峰值低于800MB。

那么你有什么限制呢?


补充说明。这段R代码:

N <- 1000000
mydata <- data.frame(
    A=sample(runif(400),N,TRUE),
    B=sample(runif(400),N,TRUE),
    C=runif(N)
)

require(reshape)
results <- cast(mydata, A~B, value="C")
write.table(as.matrix(results),na="",sep="\t",file="results.txt")

可以用不到300MB的内存来创建你想要的东西。

在我的数据上会给出警告,因为有一些A-B组合不是唯一的,但在你的数据上应该没问题。

1

当你手里只有一把锤子的时候……

从概念上讲,你想做的事情其实很简单,但因为你的数据量很大,所以在计算上会比较困难。我通常用R语言来做分析和绘图,而不是处理数据。如果我需要处理很多数据,我一般会把所有东西放到数据库里。

最近我在使用SQLite和R方面取得了不错的效果。最棒的是,你可以用R来读取数据,这样就能轻松导入大型的SPSS文件或其他SQLite处理不了但R可以处理的数据源。

http://cran.r-project.org/web/packages/RSQLite/index.html

这是我推荐的工作流程。

  1. 把你的数据导入到R中。(完成)
  2. 加载库(Library(RSQLite))
  3. 把你的数据框移动到SQLite中。
  4. 在A列和B列上创建索引。
  5. 创建一个视图来构建你的表格。
  6. 从R中查询你的视图,并把返回的结果转成表格。
1

全新的故事就需要全新的答案。

其实不需要用到defaultdict,甚至不想用,因为如果不小心使用的话,会像死亡星的拖曳光束一样消耗内存。

这段代码没有经过测试,可能连编译都不能通过;我可能在行和列之间搞混了;后面会有修正和解释……我得赶紧……

d = {}
col_label_set = set()
row_label_set = set()
input =  open("input.txt")
output = open("output.txt","w")
for line in input:
    line = line.strip()
    splat = line.split(',')
    if len(splat) != 3:
        break # error message???
    k1, k2, v = splat
    try:
        subdict = d[k1]
    except KeyError:
        subdict = {}
        d[k1] = subdict
    subdict[k2] = v
    row_label_set.add(k1)
    col_label_set.add(k2)
col_labels = sorted(col_label_set)
row_labels = sorted(row_label_set
output.write("\t")
for v in col_labels::
    output.write(v + "\t")
output.write("\n")
for r in row_labels:
    output.write(r + "\t")
    for c in col_labels:
        output.write(d[r].get(c, "") + "\t")
    output.write("\n")

更新 这是一个修正和重构后的版本,经过了一定程度的测试:

class SparseTable(object):

    def __init__(self, iterable):
        d = {}
        col_label_set = set()
        for row_label, col_label, value in iterable:
            try:
                subdict = d[row_label]
            except KeyError:
                subdict = {}
                d[row_label] = subdict
            subdict[col_label] = value
            col_label_set.add(col_label)
        self.d = d
        self.col_label_set = col_label_set

    def tabulate(self, row_writer, corner_label=u"", missing=u""):
        d = self.d
        col_labels = sorted(self.col_label_set)
        row_labels = sorted(d.iterkeys())
        orow = [corner_label] + col_labels
        row_writer(orow)
        for row_label in row_labels:
            orow = [row_label]
            subdict = d[row_label]
            for col_label in col_labels:
                orow.append(subdict.get(col_label, missing))
            row_writer(orow)

if __name__ == "__main__":

    import sys

    test_data = u"""
    3277,4733,54.1
    3278,4741,51.0
    3278,4750,28.4
    3278,4768,36.0
    3278,4776,50.1
    3278,4784,51.4
    3279,4792,82.6
    3279,4806,78.2
    3279,4814,36.4
    """.splitlines(True)

    def my_writer(row):
        sys.stdout.write(u"\t".join(row))
        sys.stdout.write(u"\n")

    def my_reader(iterable):
        for line in iterable:
            line = line.strip()
            if not line: continue
            splat = line.split(u",")
            if len(splat) != 3:
                raise ValueError(u"expected 3 fields, found %d" % len(splat))
            yield splat

    table = SparseTable(my_reader(test_data))
    table.tabulate(my_writer, u"A/B", u"....")

这是输出结果:

A/B     4733    4741    4750    4768    4776    4784    4792    4806    4814
3277    54.1    ....    ....    ....    ....    ....    ....    ....    ....
3278    ....    51.0    28.4    36.0    50.1    51.4    ....    ....    ....
3279    ....    ....    ....    ....    ....    ....    82.6    78.2    36.4

撰写回答