nun bin ich auch endlich in diesem tollen Forum angemeldet. Ich bin Wissenschaftler mit fortgeschrittenen delphi- und python-Kenntnissen, aber kein gelernter ITler (learning by doing). Mit folgendem Problem komme ich leider nicht mehr alleine weiter und würde mich freuen über Tipps:
Kontext: ich untersuche Zeitreihen von Wortfrequenzen in sehr großen Textsammlungen (Korpora) unterschiedlicher Grundgesamtheit. Zu diesem Zweck ermittle ich die Verwendung eines Wortes in den Korpora. Anschließend aggregiere und visualisiere ich die Häufigkeiten über die Zeit in verschiedenen Intervallen (D, M, Y, 5Y usw) und relativ zur jeweiligen Grundgesamtheit. Um das machen zu können, muss ich den Datensatz mit den Häufigkeiten (enthält u.a.: Datum und Text-ID eines jeden Funds) mit dem Datensatz zur jeweiligen Grundgesamtheit auf einer identischen Periodisierung mergen.
Konkret will ich das (alles via Pandas) wie folgt umsetzen:
1) Lade Datensatz als df_corpus mit Angaben zu den Textgrößen [Text-ID, date, token-len]
2) Ermittle mindate und maxdate des Datensatzes und erstelle dann je nach Bedarf ein PeriodsArray mit freq=D/M/Y/5M..., der mindate und maxdate umfasst.
3) Merge df_corpus und PeriodsArray, so dass jedes Text-Date einer Period zugeordnet werden kann. Aggreggiere dann über die Periods (sum).
4) Schritte 1 und 3 auch für den Datensatz mit allen Worttreffern als df_frequencies.
5) Merge df_corpus und df_frequencies zur Berechnung relativer Frequenzen (z.B. f pro Mio)
6) Visualisierung (plt) über period mit klarer Explikation der jeweiligen Intervallgrenzen (z.B. 10.2000-11.2000, 12.2000-01.2001 usw.)
Mein Problem steckt bei Schritt 3: Wie kann ich effektiv (!) einen df mit datetime-Spalte mit einem Periodindex oder umgewandelt mit einem df (mit Start- und Enddate einer jeden Period) mergen?
df_corpus [text1, date=01.01.2000] <-> periods mit 2M ab 1.2.1990: [01.02.1990-31.03.1990, ... 01.02.2000-31.03.2000...] => df_corpus [text1, date=01.01.2000, period=01.12.1999-31.01.2000]
Die nachfolgende Lösung via apply und lambda (in def df_datecolumn_add_periodcolumn) ist völlig ineffektiv bei großen Datensätzen. Hat jemand einen Tipp? [resample scheint mein grundsätzliches Problem nicht zu lösen; merge_asof ist ungenau; Vektorisierung bekomme ich hier nicht hin]. Vielleicht stehe ich auch einfach auf dem Schlauch. :-/
Danke und viele Grüße,
Liuniao
Code: Alles auswählen
# Generiere PeriodIndex mit festem Intervall (D, M, Q, A-DEC), das sowohl Start- als auch Enddatum enthält
def generate_time_intervals(start_date, end_date, interval):
intervals = pd.period_range(start=pd.Period(start_date, freq=interval),
end=pd.Period(end_date, freq=interval), freq=interval)
# Ergänze einen Dataframe mit einer Period-Spalte um einen String zur besseren Explikation des Intervalls
def AddPeriodStartEndStr(adfwithperiodcolumn, columnstr, strftimeformat = 'auto'):
if strftimeformat == 'auto':
if adfwithperiodcolumn[columnstr][0].freqstr[-1] == 'D':
strftimeformat = '%d.%m.%Y'
if adfwithperiodcolumn[columnstr][0].freqstr[-1] == 'M':
strftimeformat = '%m.%Y'
if adfwithperiodcolumn[columnstr][0].freqstr[-5:] == 'A-DEC':
strftimeformat = '%Y'
if adfwithperiodcolumn[columnstr][0].freqstr in ['D', 'M', 'A-DEC', 'Y']:
adfwithperiodcolumn['periodstr'] = adfwithperiodcolumn[columnstr].apply(lambda period: period.start_time.strftime(strftimeformat))
else:
adfwithperiodcolumn['periodstr'] = adfwithperiodcolumn[columnstr].apply(lambda period: period.start_time.strftime(strftimeformat) + '-' + period.end_time.strftime(strftimeformat))
return adfwithperiodcolumn
# Erstelle periods und merge mit Korpus-DF
def df_datecolumn_add_periodcolumn(adfwithdates, intervall):
def getperdiodofdate(adate, aperiodindex):
for period in aperiodindex:
if period.start_time <= adate <= period.end_time:
return period
mindate = adfwithdates['date'].min()
maxdate = adfwithdates['date'].max()
atimeintervallseries = generate_time_intervals(mindate, maxdate, intervall)
adfwithdates['period'] = adfwithdates['date'].apply(lambda x: getperdiodofdate(x, atimeintervallseries)) # <<-- ineffektiv
adfwithdates = AddPeriodStartEndStr(adfwithdates, 'period', 'auto')
return adfwithdates