Skip to main content
added 48 characters in body
Source Link

I have a matrix of fewer than 1021 rows. I'd like to take its transpose, but it is too big for GNU datamash and awk solutions to fit into memory.

MyTo keep memory overhead low, my thought is that I keep a list of read-only file pointers to the start of each row. I then read out bytes from each pointer until I hit a delimiter (tab or newline).

I have a matrix of fewer than 1021 rows. I'd like to take its transpose, but it is too big for GNU datamash and awk solutions.

My thought is that I keep a list of read-only file pointers to the start of each row. I then read out bytes from each pointer until I hit a delimiter (tab or newline).

I have a matrix of fewer than 1021 rows. I'd like to take its transpose, but it is too big for GNU datamash and awk solutions to fit into memory.

To keep memory overhead low, my thought is that I keep a list of read-only file pointers to the start of each row. I then read out bytes from each pointer until I hit a delimiter (tab or newline).

Source Link

Transpose of a very large matrix with fewer than 1021 rows with Python

I have a matrix of fewer than 1021 rows. I'd like to take its transpose, but it is too big for GNU datamash and awk solutions.

My thought is that I keep a list of read-only file pointers to the start of each row. I then read out bytes from each pointer until I hit a delimiter (tab or newline).

Because I have fewer than 1021 rows, I won't hit the usual 1024 OS-based file pointer limit.

Once I have read out a field from all file pointers, I write a newline character and start over, reading a field from all file pointers, and again, until no more bytes are available:

#!/usr/bin/env python                                                                                                                                                                                                                               

import sys
import os

try:
  in_fn = sys.argv[1]
except ValueError as ve:
  sys.exit(-1)

def get_size(fn):
  st = os.stat(fn)
  return st.st_size

#                                                                                                                                                                                                                                                   
# 1) Read in file offsets to start of new line                                                                                                                                                                                                      
# 2) Open up a file pointer to that offset                                                                                                                                                                                                          
# 3) Process each file pointer to get a value until a delimiter is hit, then write it as a row of output                                                                                                                                            
#                                                                                                                                                                                                                                                   

size = get_size(in_fn)

fps = []
new_fp = open(in_fn, 'r')
new_fp.seek(0, 0)
fps.append(new_fp)

with open(in_fn, 'r') as f:
  byte = f.read(1)
  while byte:
    if byte == '\n':
      new_offset = f.tell()
      if new_offset < size:
        new_fp = open(in_fn, 'r')
        new_fp.seek(new_offset, 0)
        fps.append(new_fp)
      else:
        break
    byte = f.read(1)

while size > 0:
  for fi, f in enumerate(fps):
    byte = f.read(1)
    size -= 1
    while byte:
      if byte == '\t' or byte == '\n':
        if fi != len(fps) - 1: sys.stdout.write('\t')
        break
      sys.stdout.write('%s' % (byte))
      byte = f.read(1)
      size -= 1
  sys.stdout.write('\n')

for f in fps:
  f.close()

Is there anything I can do to improve the performance of this? Reading and processing a set of file pointers one byte at a time seems quite expensive. However, I need to find newline characters to build offsets and file pointers. Is there a cleverer/faster way (in Python) to find the byte offsets of newlines?