Python geheugen probleem

Pagina: 1
Acties:

Onderwerpen

Vraag


Acties:
  • 0 Henk 'm!

  • utopiaBe
  • Registratie: Maart 2009
  • Niet online
Ik heb een honderdtal files van type1, een honderdtal files van type2. Elke file bevat nog eens tienduizenden lijnen met datapunten. Elk datapunt is voorzien van een ID, waarop een join dient uitgevoerd te worden om tot een enorme dataframe te komen. Ik kan daarbij enkel de library's shutil, os, re, pandas en numpy gebruiken. Ik loop onherroepelijk vast omdat ik er niet in slaag de massa data te verwerken op de manier waarop ik dit (zie onder) implementeerde. Heb al proberen inlezen om dit te parallelliseren, maar kan geen additionele libs gebruiken. Ook chunks geprobeerd, maar dat krijg ik gewoon niet goed geïmplementeerd (weet ook niet of dat de oplossing is). Het lijkt me duidelijk dat ik hier gewoon een zeer geheugenintensief ding geïmplementeerd heb, maar het is me allerminst duidelijk hoe ik dit efficiënter krijg. Zo een krak ben ik nu ook nog niet in Python. Mocht iemand me kunnen helpen, of op weg kunnen zetten -> much appreciated. Ik zit even met de handen in het haar...
Apple M1 Max, met 64Gb RAM.

Opbouw files: Filenaam bevat ID en type van data. Dat kan ik er probleemloos uithalen. Soms zitten er meer datapunten voor een ID in file type1, soms dan weer in type2. Uiteindelijk zou de resulterende frame als volgt moeten opgebouwd zijn (daar loopt het mis):

Een dataframe type1 kan van volgende vorm zijn:
ID type1
1 [1,2,3]
1 [2,3]
2 [4,5]

Een dataframe type2 kan van volgende vorm zijn:
ID type2
1 [3]
3 [2,3]
4 [4,5]

Dit zou dan een dataframe df moeten opleveren dat er uitziet als:
ID type1 type2
1 [1,2,3] [3]
1 [2,3] NaN
2 [4,5] NaN
3 NaN [2,3]
4 NaN [4,5]
...

Python 3.9 (Jupyter notebook)
Enkel volgende library's te gebruiken: shutil, os, re, pandas en numpy
...

code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
#Haal ID uit filename (werkt)
def getID(filename):
    file_split = filename.split('-')
    if (file_split[0]).isdigit():
        return int(file_split[0])

#Haal type uit filename (werkt)
def getType(filename):
    file_split = filename.split('-')
    return file_split[2]

#Haal waarden uit een bestand. Elke lijn gaat gewoon in een lijst met de respectievelijke waarden. Lengte  varieert per filetype. Dit levert dan een dataframe met in de eerste kolom de IDs en in de tweede kolom de lijsten met waarden (werkt)

def getMetrics(filename):
    contents = []
    ids = []
    with open(path + filename, 'r') as f:
        for line in f:
            temp = []
            # all files all space seperated but one which is , seperated
            linecopy = line.replace(',', ' ') 
            lineContent = linecopy.split(' ')
            length = len(lineContent)
            ids.append(getID(filename))
            for i in range(0,length):
            #rstrip to remove the annoying \n so we can convert to float right away
                temp.append(float(lineContent[i].rstrip())) 
            contents.append(temp)
    f.close()
    dictionary = {'Id':ids,'Metrics':contents}
    df=pd.DataFrame(dictionary)
    return df

#Locatie naar folder met bestanden
path = 'path/'

#Bouw nu dataframe op adv bovenstaande functies -> crasht
#De afzonderlijke dataframes (type1 en type2 krijg ik er nog uitgeperst, de merge echter niet)
def createDF(pathname):
    type1 = pd.DataFrame(columns=['Id', 'List1'])
    type2 = pd.DataFrame(columns=['Id', 'List2'])
    for filename in os.listdir(pathname):
        temp = getMetrics(filename)
        if getType(filename) == 'type1.out':          
             type1 = pd.concat([type1, temp], ignore_index=True)
        elif getType(filename) == 'type2.out':
             type2 = pd.concat([type2, temp], ignore_index=True)

    return pd.merge(type1, type2, on='Id', how='outer')

...

Alle reacties


Acties:
  • 0 Henk 'm!

  • RobIII
  • Registratie: December 2001
  • Niet online

RobIII

Admin Devschuur®

^ Romeinse Ⅲ ja!

(overleden)
Ik heb even je topictitel ("Hulp nodig met Python (big data)") aangepast zodat 'ie a) een beetje beter de lading dekt ("hulp nodig met Python" zegt zo weinig) en b) ondanks dat 't heel veel punten zijn en je vast met geheugenproblemen kampt: dit is nog enkele ordegroottes ver verwijderd van "big data" (voor zover dat überhaupt te kwantificeren is) ;)

[ Voor 17% gewijzigd door RobIII op 10-03-2023 00:07 ]

There are only two hard problems in distributed systems: 2. Exactly-once delivery 1. Guaranteed order of messages 2. Exactly-once delivery.

Je eigen tweaker.me redirect

Over mij


Acties:
  • 0 Henk 'm!

  • utopiaBe
  • Registratie: Maart 2009
  • Niet online
@RobIII Thanks. Net geen 2Gb aan sensordata vond ik al redelijk 'big', maar dat hangt inderdaad af van de definitie die gehanteerd wordt. Als dit het verduidelijkt -> ideaal.

Acties:
  • 0 Henk 'm!

  • sig69
  • Registratie: Mei 2002
  • Nu online
Ik zie de logica met id 1 niet?
Maar je hebt dus eigenlijk een database in honderden losse bestanden staan, dus ik zou zeggen: importeer het in een database!
Waarom moet het in Pyton? Waarom ben je beperkt in libs die je kan gebruiken?

Roomba E5 te koop


Acties:
  • 0 Henk 'm!

  • utopiaBe
  • Registratie: Maart 2009
  • Niet online
@sig69 Database en andere libs zijn dus geen optie. Daar zit hem net het probleem want anders is het inderdaad zo opgelost. Bedoeling is dat ik de kneepjes van Python net onder de knie krijg met de beperkte middelen die ik hier benoem. Maar ik zie hem gewoon niet. Met kleine files was dit vast geen issue, maar dat geheugen -> ik ben gewoon even niet mee hoe dat te fixen en zit er al 2 dagen op te staren. Was al blij dat wat ik had werkte (al kan er esthetisch ook wel nog eea verbeterd worden), op dat - niet onbelangrijke - detail na dus...

Wat id1 betreft (vermoed dat je het over het resulterend df hebt):
per id wordt de data gewoon toegevoegd. Type1 in eerste kolom, type2 in tweede kolom. Heeft één van de twee types minder gegevens dan de andere, dan wordt aangevuld met NaN.

[ Voor 12% gewijzigd door utopiaBe op 10-03-2023 00:27 ]


Acties:
  • 0 Henk 'm!

  • Gropah
  • Registratie: December 2007
  • Niet online

Gropah

Admin Softe Goederen

Oompa-Loompa 💩

Big data is meer dan alleen de hoeveelheid. Dat is maar 1 van de V's.

Zit er een sortering in de bestanden? Staat ID 1 altijd boven aan? Zoals je het nu inleest, lijk je dezelfde data meerdere keren in geheugen te laden. Maar is dat echt nodig?

Acties:
  • 0 Henk 'm!

  • sig69
  • Registratie: Mei 2002
  • Nu online
utopiaBe schreef op vrijdag 10 maart 2023 @ 00:24:
@sig69 Database en andere libs zijn dus geen optie.
Maar waarom niet? Ik vind dat vreemd. Je moet de juiste tools voor de job gebruiken, anders krijg je dus dit soort dingen.
Ik wil niet perse zeggen dat een database de oplossing is (ik snap nu wat je beoogde resultaat is), maar waarom die beperkingen?

[ Voor 18% gewijzigd door sig69 op 10-03-2023 01:02 ]

Roomba E5 te koop


Acties:
  • 0 Henk 'm!

  • fopjurist
  • Registratie: Mei 2021
  • Niet online

fopjurist

mr.drs. fopjurist

Het inlezen kan makkelijker via read_csv en df.values.tolist(). Dat scheelt geen geheugen maar maakt je code wel leesbaarder.

De dataframe type1 kun je efficiënter opbouwen. Je breidt een dataframe nu stapje voor stapje uit terwijl je hem ook in 1x kunt opbouwen:
code:
1
2
files_type_1 = [filename for filename in os.listdir(pathname) if getType(filename) == 'type1.out']
type1 = pd.concat((getMetrics(filename) for filename in files_type_1), ignore_index=True)


Met pd.merge krijg je niet het resultaat uit je voorbeeld omdat er niet aan deze regel wordt voldaan:
Heeft één van de twee types minder gegevens dan de andere, dan wordt aangevuld met NaN.
Als er in type 1 vijf rijen met ID=1 en in type 2 zes rijen met ID=1, krijg je met je huidige code 30 rijen met ID=1 terwijl het er maar 6 rijen zouden moeten zijn. Zijn er ID's die heel vaak voorkomen, wat kan verklaren waarom je onvoldoende geheugen hebt om de huidige code uit te voeren?

Hoeveel geheugen heb je beschikbaar en op welke regel gaat het mis?

Beschermheer van het consumentenrecht


Acties:
  • 0 Henk 'm!

  • eheijnen
  • Registratie: Juli 2008
  • Niet online
Geen return value mogelijk. Gaat dit altijd goed, of hoort daar nog een else bij?
Python:
1
2
3
4
def getID(filename):
    file_split = filename.split('-')
    if (file_split[0]).isdigit():
        return int(file_split[0])


Klapt het script eruit en zo ja zet dan de foutmelding in de topic start erbij.
Plaats eens wat sample data in de topic start.
Zet eens in de TS hoeveel memory de pc heeft.
Werkt het met kleinere hoeveelheden wel (10 of 20MB aan data)?
Als het script draait hoe loopt het memory gebruik dan op (task manager)?

[ Voor 6% gewijzigd door eheijnen op 10-03-2023 09:00 ]

Wie du mir, so ich dir.


Acties:
  • 0 Henk 'm!

  • Janoz
  • Registratie: Oktober 2000
  • Laatst online: 22-07 01:20

Janoz

Moderator Devschuur®

!litemod

Ik denk dat @Gropah alvast de belangrijkste vraag gesteld heeft. Als de id's namelijk gesorteerd zijn is dit heel simpel streaming op te lossen door een algoritme dat lijkt op de daadwerkelijke merge stap van het merge-sort algoritme

Ken Thompson's famous line from V6 UNIX is equaly applicable to this post:
'You are not expected to understand this'


Acties:
  • 0 Henk 'm!

  • utopiaBe
  • Registratie: Maart 2009
  • Niet online
Ik werk met een MacBook Pro M1 Max, met 64Gb RAM. Dat mag echter niet de referentie zijn. Zou echt op een meer standaardmachine ook moeten draaien.

@Gropah Ik heb even het geheugengebruik toegevoegd net voor de crash (='Kernel lijkt te zijn gestopt. Hij wordt automatisch herstart'). Dat is duidelijk niet ok. Afbeeldingslocatie: https://tweakers.net/i/3_28z6jp943C23RD4gxoIWBTzGU=/full-fit-in/4000x4000/filters:no_upscale():fill(white):strip_exif()/f/image/YNKqZ1UsgV3EQAnFQ3gMSzUb.png?f=user_large
Er zit een sortering in de bestanden, al lijkt het me gevaarlijk daar op af te gaan. Kan natuurlijk wel iets inbouwen dat ze sowieso gesorteerd worden. Er zijn wel altijd 2 bestanden per id.

@fopjurist Je hebt trouwens gelijk wat die outer merge betreft (daar loopt het ook al fout dus :s). Een merge lijkt hier helemaal niet de oplossingen, maar dan wordt het nog erger aangezien ik dacht dat een merge net redelijk snel en efficient zou (moeten) gaan.
IDs komen sowieso vaak voor, aangezien ze geassocieerd zijn met de inhoud van de files die aardig wat lijnen bevatten en elke lijn moet als lijst in een kolom in het dataframe, samen met de id (in een andere kolom). Die id komt uit de filename. Die efficiëntere opbouw ga ik inderdaad al voorzien. Daar was echter nog niet eens een issue, al is het zeker een betere oplossing dan de mijne. Het is pas bij het samenvoegen dat ik met een probleem te maken krijg.

@eheijnen Ik kan idd een else toevoegen. Altijd zo netjes, maar dat levert zeker geen issues hier.

@Janoz die streamingtip bekijk ik even. Dat ken ik niet. Dit is les 3 ve cursus data analyse na een zeer elementaire python-cursus. De insteek is meer 'trek uw plan en gebruik Google', want echt Python wordt er niet meer in gegeven. Dat zoeken doe ik ook intensief. Wil er me hier niet makkelijk vanaf maken en het ook écht vatten, maar loop duidelijk toch tegen limieten aan. Ben hier dus zwaar zoekende. Je tip wordt dus alvast geapprecieerd. Ga ik even mee aan de slag.

Omdat het gevraagd werd even een voorbeeld van de files (sterk verkort want zitten vaak > 1 miljoen lijnen in). Niet elk bestand is dus even lang:
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
1-proper-type1.out (1 is id, type1.out type en inhoud van elke lijn kan in lijst (met floats)):
0.000000 -1.000000
30.000000 -1.000000
60.000000 -1.000000
90.000000 -1.000000
120.000000 -1.000000
150.000000 -1.000000
180.000000 -1.000000
210.000000 -1.000000
240.000000 -1.000000
270.000000 -1.000000
300.000000 -1.000000

1-proper-type2.out:
0.015948 0.403931 0.449005 -0.796860
0.036006 0.403915 0.448029 -0.795395
0.055885 0.404907 0.446548 -0.795853
0.075883 0.408356 0.447525 -0.796768
0.095875 0.406891 0.444580 -0.796280
0.115847 0.406876 0.446060 -0.794846
0.136011 0.406372 0.446060 -0.793381
0.156050 0.407867 0.447037 -0.796295
0.175944 0.409363 0.449982 -0.799210
0.195947 0.405411 0.449493 -0.798294
0.215958 0.405396 0.448517 -0.795364

[ Voor 4% gewijzigd door utopiaBe op 10-03-2023 10:16 ]


Acties:
  • 0 Henk 'm!

  • RobIII
  • Registratie: December 2001
  • Niet online

RobIII

Admin Devschuur®

^ Romeinse Ⅲ ja!

(overleden)
utopiaBe schreef op vrijdag 10 maart 2023 @ 10:02:
Er zit een sortering in de bestanden, al lijkt het me gevaarlijk daar op af te gaan. Kan natuurlijk wel iets inbouwen dat ze sowieso gesorteerd worden. Er zijn wel altijd 2 bestanden per id.
Goed, maar met alle 'beperkingen' die je hebt: mag je dan bijvoorbeeld wel eerst een 'slag' doen en door alle bestanden heen kauwen en ze alvast sorteren voordat je ze daadwerkelijk gaat gebruiken zodat je je daarna tijdens 't verwerken van die data daar niet meer om hoeft te bekommeren om volgorde (want gegarandeerd gesorteerd) en je algoritme dus kunt vereenvoudigen? Met andere woorden: mag je wel je data bijvoorbeeld "pre-processen"?

[ Voor 4% gewijzigd door RobIII op 10-03-2023 10:20 ]

There are only two hard problems in distributed systems: 2. Exactly-once delivery 1. Guaranteed order of messages 2. Exactly-once delivery.

Je eigen tweaker.me redirect

Over mij


Acties:
  • 0 Henk 'm!

  • Gropah
  • Registratie: December 2007
  • Niet online

Gropah

Admin Softe Goederen

Oompa-Loompa 💩

Janoz schreef op vrijdag 10 maart 2023 @ 08:19:
Ik denk dat @Gropah alvast de belangrijkste vraag gesteld heeft. Als de id's namelijk gesorteerd zijn is dit heel simpel streaming op te lossen door een algoritme dat lijkt op de daadwerkelijke merge stap van het merge-sort algoritme
Dit was inderdaad waar ik aan zat te denken. Grootste nadeel is dat je je IO minder batcht, maar als je hierdoor je programma wel kan laten draaien...
RobIII schreef op vrijdag 10 maart 2023 @ 10:19:
[...]

Goed, maar met alle 'beperkingen' die je hebt: mag je dan bijvoorbeeld wel eerst een 'slag' doen en door alle bestanden heen kauwen en ze alvast sorteren voordat je ze daadwerkelijk gaat gebruiken zodat je je daarna tijdens 't verwerken van die data daar niet meer om hoeft te bekommeren om volgorde (want gegarandeerd gesorteerd) en je algoritme dus kunt vereenvoudigen? Met andere woorden: mag je wel je data bijvoorbeeld "pre-processen"?
Gezien het een cursus data analyse is, zou ik het raar vinden als je niet mag preprocessen.

Acties:
  • 0 Henk 'm!

Anoniem: 80910

Ik zie dat je 100GB geheugen gebruikt. Ik zou zeggen probeer het eerst met 1 bestand check de output en herhaal het proces. Check geheugen gebruik bij weinig source en schaal dan op (meerdere bestanden)

Acties:
  • 0 Henk 'm!

  • utopiaBe
  • Registratie: Maart 2009
  • Niet online
@RobIII we mogen os gebruiken, dus via os.listdir kan ik dat normaal wel inbouwen (lijst van files die ik dan sorteer en doorloop).
Preprocessen: het is een cursus data analyse, maar daadwerkelijke data analyse werd er nog niet echt behandeld. Veel rond netwerken, ethische aspecten en welke toestellen welke sensorische data kunnen opleveren, dat wel. Parallel dus dit soort oefeningen (die tot nu ook wel goed liepen, maar helaas... zit ik nu vast). Beetje raar georganiseerd, maar het is wat het is en moet erdoor.

We mochten er wel van uitgaan dat deze databestanden wel 'schoon' zijn. Geen missende waarden, geen overbodige data,... Meer preprocessen lijkt me dan ook niet mogelijk hier, toch niet zonder data te verliezen. Ondertussen ah inlezen in dat streamen, maar blijkt ook een extra import te eisen (pandas_streaming.df). Desnoods moet het dan maar zo, dan kan ik toch verder met de rest. Dask lijkt me dan ook nog een optie (als ik dan toch de regels al moet overtreden :s). Het is nl knudde als je bij vraag 1 van de reeks al vastloopt (rest lijkt me gelukkig wel te doen, maar moet mijn df wel kunnen bevragen). Maar het blijft knagen dat er ergens een eenvoudigere oplossing moet zijn, zonder extra zaken in te laden :X .

Edit: volgens mij ben ik gewoon te '2D' aan het denken ook. Even anders proberen benaderen. Wil echt extra imports voorkomen. Pfff, bijna 20 jaar na afstuderen even een cursusje meepikken valt wat heavier dan verwacht. Herinner me dat vroeger concepten toch eerst werden uitgelegd voor je ze moest toepassen...

[ Voor 21% gewijzigd door utopiaBe op 10-03-2023 19:36 ]


Acties:
  • 0 Henk 'm!

  • utopiaBe
  • Registratie: Maart 2009
  • Niet online
Haha! Nog en dag op verscheten, maar het werk en zonder extra import :-). Even in 3 dimensies gedacht ipv 2. Als je dataframes in dataframes stopt, heb je automatisch NaNs wanneer een df in een cell minder lang is dan een ander. Dus: rijen werden de patiënten, kolommen de types metingen en de cellen een nieuw dataframe met alle meetwaarden voor dat type.

Veel minder rijen, en makkelijker te mergen. Esthetisch nog niet helemaal top, maar dat is voor na de functionaliteit. Maar man, in een simpele DB was dit toch een smak eenvoudiger geweest :s.

@Gropah Je weet dat die V's (varianten van 3 tot 7 als ik me niet vergis) hun oorsprong vinden in de commerciële wereld? Die worden zeker niet overal gevolgd. Een andere definitie is dat men van big data spreekt van zodra men deze niet meer met standaard programma's kan manipuleren/analyseren. Dan blijft de vraag natuurlijk wel wat die standaard programma's zijn. En soms wordt het inderdaad wel gek. Op de UGent spreken ze bv al van Big Data als het over gaat over hotspots mappen op basis van criminaliteitsstatistiekjes binnen een stad. Noch zoveel criminaliteit, noch zoveel parameters gaan daarmee gepaard om zoiets te verantwoorden. Maar blijkbaar verkoopt het wel bij beleidsmakers :s.

Acties:
  • +1 Henk 'm!

  • Ben(V)
  • Registratie: December 2013
  • Laatst online: 20:12
Voor dit soort problemen gebruik je memory mapped file acess.
In numpy zit een module die dat volkomen transparant voor je doet.

https://numpy.org/devdocs...nerated/numpy.memmap.html

All truth passes through three stages: First it is ridiculed, second it is violently opposed and third it is accepted as being self-evident.


Acties:
  • 0 Henk 'm!

  • utopiaBe
  • Registratie: Maart 2009
  • Niet online
@Ben(V) Dat lijkt me inderdaad een goeie om mee te nemen voor de toekomst. Op t eerste zicht kon ik ook die nu niet gebruiken omdat ik dan een file op de disk moest kunnen schrijven (was nog een restrictie die ik weliswaar niet vermeldde), of een extra import om dat te voorkomen (wat dus ook niet kon).

Enfin, uiteindelijk werkt het nu redelijk snel en kon ik er alle analyses uitpuren die ik nodig had. Ben dus weer ff happy met het resultaat. Kleine stapjes, but getting there. En de tips die ik hier meekrijg, ook al kan ik ze niet meteen meenemen, helpen zeker ook om dit onder de knie te krijgen.
Pagina: 1