tags:

views:

133

answers:

5

$$I need to get the numbers of one line randomly, and put each line in other array,then get the numbers of one col.

I have a big file, more than 400M. In that file, there are 13496*13496 number, means 13496 rows and 13496 cols. I want to read them to a array. This is my code:

_L1 = [[0 for col in range(13496)] for row in range(13496)]
_L1file = open('distanceCMD.function.txt')
while (i<13496):
    print "i="+str(i)
    _strlf = _L1file.readline()
    _strlf = _strlf.split('\t')
    _strlf = _strlf[:-1]
    _L1[i] = _strlf
    i += 1
_L1file.close()

And this is my error massage:

MemoryError:
File "D:\research\space-function\ART3.py", line 30, in <module>
  _strlf = _strlf.split('\t')
+7  A: 

you might want to approach your problem in another way. Process the file line by line. I don't see a need to store the whole big file into array. Otherwise, you might want to tell us what you are actually trying to do.

for line in open("400MB_file"):
     # do something with line.

Or

f=open("file")
for linenum,line in enumerate(f):
    if linenum+1 in [2,3,10]:
         print "there are ", len(line.split())," columns" #assuming you want to split on spaces
         print "100th column value is: ", line.split()[99]
    if linenum+1>10:
         break # break if you want to stop after the 10th line
f.close()
ghostdog74
Because I need to select some numbers by row number.eg: I want to know all the numbers which on the 3th line.
flint
So just iterate through the file like Ghostdog74 says and collect all numbers on the 3rd row.
Tim Pietzcker
If you need a particular row you could write a function to scan to that row in the file and read just that row. It might not be the fastest way but will avoid loading file in memory.
Dave Turvey
But when I get the numbers, I also need to know the numbers of cols. Eg: I get the 3th line, 2ed line and 10th line. I need to get the number of 100th col in each line.
flint
@flint, see my edit.
ghostdog74
I just want to say, the number of rows will increase. So...
flint
My program is a testing program. I need to random one line first time put the numbers in L1[] and from second time I need to random three lines, like 123, 421 and 541. Then get the number of the 123th col, 421th col and 541th col from first line. Then select one from them, like 421. Put the 421th row from the file.
flint
But I can not say I need to run it how many times. Because it is a ramdom selection.
flint
i believe you know how to append to lists. for random selection you can use `random` module. To go back to the beginning of file to process again, you can use `f.seek(0)`
ghostdog74
I mean if I use your way which take file line by line, and then translate them to number by number. A first it will be fine, but when I run it a lot of times, RAM will be dead.
flint
A: 

MemoryError exception:

Raised when an operation runs out of memory but the situation may still be rescued (by deleting some objects). The associated value is a string indicating what kind of (internal) operation ran out of memory. Note that because of the underlying memory management architecture (C’s malloc() function), the interpreter may not always be able to completely recover from this situation; it nevertheless raises an exception so that a stack traceback can be printed, in case a run-away program was the cause.

It seems that, at least in your case, reading the entire file into memory is not a doable option.

plok
+3  A: 

This is a simple case of your program demanding more memory than is available to the computer. An array of 13496x13496 elements requires 182,142,016 'cells', where a cell is a minimum of one byte (if storing chars) and potentially several bytes (if storing floating-point numerics, for example). I'm not even taking your particular runtimes' array metadata into account, though this would typically be a tiny overhead on a simple array.

Assuming each array element is just a single byte, your computer needs around 180MB of RAM to hold it in memory in its' entirety. Trying to process it could be impractical.

You need to think about the problem a different way; as has already been mentioned, a line-by-line approach might be a better option. Or perhaps processing the grid in smaller units, perhaps 10x10 or 100x100, and aggregating the results. Or maybe the problem itself can be expressed in a different form, which avoids the need to process the entire dataset altogether...?

If you give us a little more detail on the nature of the data and the objective, perhaps someone will have an idea to make the task more manageable.

Jonners
I suggest he should put his data in a database, like SQLite. That way the DBMS does the dirty work and he can have a good random access to this giant table.
Morgaelyn
Uh, how did you come up with the number 33,175,713,992,544,256?
unwind
Simple - I hit the 'OK' button on the calculator too many times. ;)The correct answer is of course 182,142,016 which is a much smaller number, roughly 180 megabytes. Which is not really supercomputer scale, but still might blow the local memory constraint (we don't know what the actual platform is here). The principle of my answer remains the same, even if my calculation was horribly broken. Hey, it's Friday, and it's been a long week! ;)
Jonners
@Jonners: Thanks, I was getting a bit worried for my own Calculator skills, there. I think you should edit, since this answer is based on a not quite true statement ...
unwind
Done. Reworked to correct subjectiveness based on erroneous calculation result.
Jonners
+3  A: 

Short answer: the Python object overhead is killing you. In Python 2.x on a 64-bit machine, a list of strings consumes 48 bytes per list entry even before accounting for the content of the strings. That's over 8.7 Gb of overhead for the size of array you describe. On a 32-bit machine it'll be a bit better: only 28 bytes per list entry.

Longer explanation: you should be aware that Python objects themselves can be quite large: even simple objects like ints, floats and strings. In your code you're ending up with a list of lists of strings. On my (64-bit) machine, even an empty string object takes up 40 bytes, and to that you need to add 8 bytes for the list pointer that's pointing to this string object in memory. So that's already 48 bytes per entry, or around 8.7 Gb. Given that Python allocates memory in multiples of 8 bytes at a time, and that your strings are almost certainly non-empty, you're actually looking at 56 or 64 bytes (I don't know how long your strings are) per entry.

Possible solutions:

(1) You might do (a little) better by converting your entries from strings to ints or floats as appropriate.

(2) You'd do much better by either using Python's array type (not the same as list!) or by using numpy: then your ints or floats would only take 4 or 8 bytes each.

Since Python 2.6, you can get basic information about object sizes with the sys.getsizeof function. Note that if you apply it to a list (or other container) then the returned size doesn't include the size of the contained list objects; only of the structure used to hold those objects. Here are some values on my machine.

>>> import sys
>>> sys.getsizeof("")
40
>>> sys.getsizeof(5.0)
24
>>> sys.getsizeof(5)
24
>>> sys.getsizeof([])
72
>>> sys.getsizeof(range(10))  # 72 + 8 bytes for each pointer
152
Mark Dickinson
A: 

Replace this:

_strlf = _strlf[:-1]

with this:

_strlf = [float(val) for val in _strlf[:-1]]

You are making a big array of strings. I can guarantee that the string "123.00123214213" takes a lot less memory when you convert it to floating point.

You might want to include some handling for null values.

You can also go to numpy's array type, but your problem may be too small to bother.

wisty