我有一组数据(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“表(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")
答案 0 :(得分:1)
当你拥有的只是一把锤子。 。 。 。
从概念上讲,您尝试做的很简单,但由于数据的大小,计算难度很大。我倾向于使用R来获得它的分析和图形容量,而不是它的数据争论技能。当我需要移动大量数据时,我通常只是将所有内容都放在数据库中。
最近我在SQLite和R上取得了相当大的成功。最好的部分是你可以实际使用R来读取数据,这样可以轻松导入大型SPSS文件或其他SQLite数据源。真的可以处理,但R可以。
http://cran.r-project.org/web/packages/RSQLite/index.html
这是我推荐的工作流程。
答案 1 :(得分: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。
那么你有什么限制?
EDIT。这段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组合,但对你来说应该没问题。
答案 2 :(得分: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
答案 3 :(得分:0)
如果你可以在R中使用table(x,y,z)
,那么如何尝试处理这些庞大数据集的R内存包呢?使用程序包bigmemory中的read.big.matrix
函数读取数据集和程序包bigtabulate中的bigtable
函数以创建表。
请参阅vignettes。
答案 4 :(得分:0)
您想要的输出示例对我来说看起来不像是一个三向列联表。这将是从(key1,key2,key3)到出现次数的映射。您的示例看起来像是从(key1,key2)到某个数字的映射。 你没有说当(key1,key2)重复时该做什么:平均,总计,还有什么?
假设您想要使用嵌套的defaultdict
来实现总体,这是一种节省内存的方法:
>>> 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)两个数据结构,一个用于总计,一个用于计数,然后执行“average = total - count”(2)对数据进行排序前两列,用户itertools.groupby一起收集重复项,进行计算,并将结果添加到“平均”数据结构中。哪种方法使用较少的内存很难说; Python是Python,你可以很快地尝试。
答案 5 :(得分:0)
dict的一个小子类可以为您提供一个使用该表的舒适对象。 在桌面PC上500.000项应该不是问题 - 如果你碰巧有500.000.000项,类似的类可以从键映射到文件本身的位置(实现起来会更酷:-))< / p>
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"))