【问题标题】:Script to convert Huge Three column table into table将巨大的三列表格转换为表格的脚本
【发布时间】:2010-10-28 15:23:46
【问题描述】:

我有一组数据(CSV 文件),格式为以下 3 列:

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)”

问题是我的数据集非常庞大(总行数超过 500,000 行,在 A 和 B 中大约有 400 个不同的因素。(OOo、MSO 和 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")

【问题讨论】:

  • 考虑使用 numpy 数组,它针对更大的数据集进行了优化scipy.org/…
  • 我无法看到这个问题的三方面性质。你的表不是 Z[A,B] = C 的 Z 吗?如果 A 和 B 有 400 个因子,那么 Z 只有 400*400。您是否对相同的 A、B 对进行平均?我在这里缺少第三个维度。很像道路杀手。
  • 是的,抱歉我的描述有误。我只需要将 3 列表映射到行/列/值表。理想情况下,我需要一个带有 A、B、C 的 CSV 文件的脚本,并以所示的表格格式写入相同的数据。
  • 所以你的输出矩阵是真正的 3D 矩阵,如 Z[A,B,C],没有存储在 Z[A,B,C] 中的值,它只是存在吗?还是不清楚。告诉我们你想用这个做什么可能会更容易,然后我们可以找到更好的解决方案。显然你不想打印出来......
  • 嗯...实际上进行转换的想法是以这种特定方式“呈现”数据。将 A、B、C 视为一个图,其中 A 和 B 是两个节点,C 是节点之间弧的“标签”。这个想法是以矩阵的形式呈现数据。

标签: python r algorithm scripting import-from-csv


【解决方案1】:

全新的故事值得一个全新的答案。

不需要defaultdict,甚至不需要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

【讨论】:

  • 耶!今天你是我的英雄。是的,这就像 acharm 一样工作(只是在一些小的更正 :: 和缺失之后)非常感谢!
  • @xtracto:我很高兴能帮上忙。请留下关于次要更正的评论,我会在早上整理答案(这是 TZ 的睡眠时间),所以我们不会留下错误的非编译答案让其他人绊倒。
【解决方案2】:

当你只有一把锤子时。 . . . .

从概念上讲,您尝试做的事情很简单,但由于数据量大,计算起来很困难。我倾向于使用 R 的分析和图形能力,而不是数据整理技能。当我需要移动一堆数据时,我通常只是将所有内容都放入数据库中。

最近我在使用 SQLite 和 R 方面取得了相当大的成功。最好的部分是您实际上可以使用 R 来读取数据,这使得导入大型 SPSS 文件或 SQLite 可以使用的其他数据源变得容易'不能真正处理,但 R 可以。

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

这是我推荐的工作流程。

  1. 将数据导入 R。(完成)
  2. 库(RSQLite)
  3. 将数据框移至 SQLite。
  4. 在 A 列和 B 列上创建索引。
  5. 创建用于构建表格的视图。
  6. 从 R 中查询您的视图并将返回值强制转换为表格。

【讨论】:

  • 将所有数据转储到 SQLite 的另一个不错的方面 - 一旦您的数据在 SQLite 中,您可以轻松地使用 Python 或 Perl 来处理您的数据。您甚至可以使用其他工具,例如 SOFA Statistics。与 SQLite 的连接非常普遍。相比之下,存储在 R 的本机数据结构中的数据不容易被其他编程语言或工具访问。
【解决方案3】:

在 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 的 RAM 创建您想要的内容。

根据我的数据,它给出警告,因为存在非唯一的 A-B 组合,但对你来说应该没问题。

【讨论】:

  • 这些都是整数向量。如果转换为数字,它仍然有效吗?
  • @Joshua 我用rnorm(400) 替换了1:400,它仍然有效。它使用更多 RAM ~1.1GB。
  • 这是用我的数据集部分测试的:summary(mydata) > names(mydata) [1] "A" "B" "C" > nrow( mydata) [1] 180227 newtab
【解决方案4】:

如果您可以在 R 中使用 table(x,y,z),那么尝试使用 R 处理如此庞大的数据集的内存不足的包怎么样?使用包bigmemory中的read.big.matrix函数读取数据集,使用包bigtabulate中的bigtable函数创建表。

见vignettes。

【讨论】:

    【解决方案5】:

    在我看来,您的期望输出示例不像 3 路列联表。那将是从 (key1, key2, key3) 到出现次数的映射。您的示例看起来像是从 (key1, key2) 到某个数字的映射。 你没有说当 (key1, key2) 重复时该怎么做:平均值、总数还是其他?

    假设您想要一个总数,这是 Python 中的一种节省内存的方法,使用嵌套的defaultdicts:

    >>> from collections import defaultdict as dd
    >>> d = dd(lambda: dd(float))
    >>> d[3277][4733] += 54.1
    >>> d
    defaultdict(<function <lambda> at 0x00D61DF0>, {3277: defaultdict(<type 'float'>, {4733: 54.1})})
    >>> d[3278][4741] += 51.0
    >>> d
    defaultdict(<function <lambda> at 0x00D61DF0>, {3277: defaultdict(<type 'float'>, {4733: 54.1}), 3278: defaultdict(<type 'float'>, {4741: 51.0})})
    >>>
    

    另一种方法是使用单个 defaultdict 和复合键:

    >>> d2 = dd(float)
    >>> d2[3277,4733] += 54.1
    >>> d2
    defaultdict(<type 'float'>, {(3277, 4733): 54.1})
    >>> d2[3278,4741] += 51.0
    >>> d2
    defaultdict(<type 'float'>, {(3277, 4733): 54.1, (3278, 4741): 51.0})
    >>>
    

    如果您在将这些数据组合在一起后说出您想如何处理这些数据,这可能会有所帮助...

    如果您想要(例如)一个平均值,您有两种选择:(1) 两种数据结构,一种用于总计,一种用于计数,然后执行“平均值 = 总计 - 计数”(2) 在前 2 列,用户 itertools.groupby 将您的重复项收集在一起,进行计算,并将结果添加到您的“平均”数据结构中。很难说这些方法中哪一种会使用更少的内存。 Python 是 Python,你可以很快地尝试两者。

    【讨论】:

    • 感谢您的回复...确实,我正在寻找的不是列联表,而是 C 到 A 和 B 在行、列中的映射。感谢您的指正。因此,我不需要添加任何值,而只需 position 正确行/列组合中的值。也没有重复的键。理想情况下,我正在寻找一种简单的方法将带有 A、B、C 的输入文件转换为带有表格的输出文件。
    【解决方案6】:

    dict 的一个小子类可以为您提供一个舒适的对象来处理表格。 500.000 个项目在台式 PC 上应该不是问题 - 如果您碰巧有 500.000.000 个项目,类似的类可以从键映射到文件本身的位置(实现起来会更酷:-))

    import csv
    class ContingencyTable(dict):
        def __init__(self):
            self.a_keys=set()
            self.b_keys=set()
            dict.__init__(self)
        def __setitem__(self, key,value):
            self.a_keys.add(key[0])
            self.b_keys.add(key[1])
            dict.__setitem__(self, key, value)
        def feed(self, file):
            reader = csv.reader(file)
            reader.next()
            for a, b, c in reader:
                self[int(a),int(b)] = float(c)
    
    table = ContingencyTable()
    table.feed(open("yourfile.csv"))
    

    【讨论】:

      猜你喜欢
      • 2022-12-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-08-08
      • 2020-07-03
      • 1970-01-01
      相关资源
      最近更新 更多