Parsen – chatgpz.de – KI-Tools & Praxiswissen https://chatgpz.de Unabhängige Tests, Anleitungen und Hintergründe zu KI-Tools. Sat, 02 May 2026 19:28:51 +0000 de-DE hourly 1 https://wordpress.org/?v=6.4.2 234900186 Eine Codierungsimplementierung zum Parsen, Analysieren, Visualisieren und Feinabstimmen von Agent Reasoning Traces mithilfe des Lambda/Hermes-Agent-Reasoning-Traces-Datensatzes https://chatgpz.de/artificial-intelligence/eine-codierungsimplementierung-zum-parsen-analysieren-visualisieren-und-feinabstimmen-von-agent-reasoning-traces-mithilfe-des-lambda-hermes-agent-reasoning-traces-datensatzes/ https://chatgpz.de/artificial-intelligence/eine-codierungsimplementierung-zum-parsen-analysieren-visualisieren-und-feinabstimmen-von-agent-reasoning-traces-mithilfe-des-lambda-hermes-agent-reasoning-traces-datensatzes/#respond Sat, 02 May 2026 19:28:51 +0000 https://chatgpz.de/artificial-intelligence/eine-codierungsimplementierung-zum-parsen-analysieren-visualisieren-und-feinabstimmen-von-agent-reasoning-traces-mithilfe-des-lambda-hermes-agent-reasoning-traces-datensatzes/ [ad_1]

In diesem Tutorial erkunden wir das Lambda/hermes-agent-reasoning-traces-Datensatz um zu verstehen, wie agentenbasierte Modelle denken, Instruments verwenden und Antworten in Gesprächen mit mehreren Runden generieren. Wir beginnen mit dem Laden und Untersuchen des Datensatzes und untersuchen seine Struktur, Kategorien und Konversationsformat, um eine klare Vorstellung von den verfügbaren Informationen zu erhalten. Anschließend erstellen wir einfache Parser, um Schlüsselkomponenten wie Argumentationsspuren, Toolaufrufe und Toolantworten zu extrahieren und so internes Denken von externen Aktionen zu trennen. Außerdem analysieren wir Muster wie die Häufigkeit der Instrument-Nutzung, die Gesprächslänge und Fehlerraten, um das Agentenverhalten besser zu verstehen. Wir erstellen auch Visualisierungen, um diese Tendencies hervorzuheben und die Analyse intuitiver zu gestalten. Abschließend bereiten wir den Datensatz für das Coaching vor, indem wir ihn in ein modellfreundliches Format konvertieren, sodass er für Aufgaben wie überwachte Feinabstimmung geeignet ist.

!pip -q set up -U datasets pandas matplotlib seaborn transformers speed up trl


import json, re, random, textwrap
from collections import Counter, defaultdict
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from datasets import load_dataset, concatenate_datasets


random.seed(0)


CONFIG = "kimi"
ds = load_dataset("lambda/hermes-agent-reasoning-traces", CONFIG, break up="prepare")
print(ds)
print("Config:", CONFIG, "| Fields:", ds.column_names)
print("Classes:", sorted(set(ds("class"))))


COMPARE_BOTH = False
if COMPARE_BOTH:
   ds_kimi = load_dataset("lambda/hermes-agent-reasoning-traces", "kimi", break up="prepare")
   ds_glm  = load_dataset("lambda/hermes-agent-reasoning-traces", "glm-5.1", break up="prepare")
   ds_kimi = ds_kimi.add_column("supply", ("kimi") * len(ds_kimi))
   ds_glm  = ds_glm.add_column("supply", ("glm-5.1") * len(ds_glm))
   ds = concatenate_datasets((ds_kimi, ds_glm)).shuffle(seed=0)
   print("Mixed:", ds, "→ counts:", Counter(ds("supply")))


pattern = ds(0)
print("n=== Pattern 0 ===")
print("id        :", pattern("id"))
print("class  :", pattern("class"), "/", pattern("subcategory"))
print("process      :", pattern("process"))
print("turns     :", len(pattern("conversations")))
print("system(0) :", pattern("conversations")(0)("worth")(:220), "...n")

Wir installieren alle erforderlichen Bibliotheken und importieren die notwendigen Module, um unsere Umgebung einzurichten. Anschließend laden wir den Datensatz „lambda/hermes-agent-reasoning-traces“ und überprüfen seine Struktur, Felder und Kategorien. Non-compulsory kombinieren wir auch mehrere Datensatzkonfigurationen und untersuchen eine Stichprobe, um das Konversationsformat zu verstehen.

THINK_RE     = re.compile(r"<assume>(.*?)</assume>", re.DOTALL)
TOOL_CALL_RE = re.compile(r"<tool_call>s*({.*?})s*</tool_call>", re.DOTALL)
TOOL_RESP_RE = re.compile(r"<tool_response>s*(.*?)s*</tool_response>", re.DOTALL)


def parse_assistant(worth: str) -> dict:
   ideas = (t.strip() for t in THINK_RE.findall(worth))
   calls = ()
   for uncooked in TOOL_CALL_RE.findall(worth):
       strive:
           calls.append(json.hundreds(uncooked))
       besides json.JSONDecodeError:
           calls.append({"identify": "<malformed>", "arguments": {}})
   last = TOOL_CALL_RE.sub("", THINK_RE.sub("", worth)).strip()
   return {"ideas": ideas, "tool_calls": calls, "last": last}


def parse_tool(worth: str):
   uncooked = TOOL_RESP_RE.search(worth)
   if not uncooked: return {"uncooked": worth}
   physique = uncooked.group(1)
   strive:    return json.hundreds(physique)
   besides: return {"uncooked": physique}


first_gpt = subsequent(t for t in pattern("conversations") if t("from") == "gpt")
p = parse_assistant(first_gpt("worth"))
print("Thought preview :", (p("ideas")(0)(:160) + "...") if p("ideas") else "(none)")
print("Instrument calls       :", ((c.get("identify"), record(c.get("arguments", {}).keys())) for c in p("tool_calls")))

Wir definieren Regex-basierte Parser, um Argumentationsspuren, Toolaufrufe und Toolantworten aus dem Datensatz zu extrahieren. Wir verarbeiten Hilfsmeldungen, um Gedanken, Handlungen und Endergebnisse auf strukturierte Weise zu trennen. Anschließend testen wir den Parser anhand einer Beispielkonversation, um sicherzustellen, dass die Extraktion ordnungsgemäß funktioniert.

N = 3000
sub = ds.choose(vary(min(N, len(ds))))


tool_calls         = Counter()
parallel_widths    = Counter()
thoughts_per_turn  = ()
calls_per_traj     = ()
errors_per_traj    = ()
turns_per_traj     = ()
cat_counts         = Counter()


for ex in sub:
   cat_counts(ex("class")) += 1
   n_calls = n_err = 0
   turns_per_traj.append(len(ex("conversations")))
   for t in ex("conversations"):
       if t("from") == "gpt":
           p = parse_assistant(t("worth"))
           thoughts_per_turn.append(len(p("ideas")))
           if p("tool_calls"):
               parallel_widths(len(p("tool_calls"))) += 1
               for c in p("tool_calls"):
                   tool_calls(c.get("identify", "<unknown>")) += 1
               n_calls += len(p("tool_calls"))
       elif t("from") == "software":
           r = parse_tool(t("worth"))
           blob = json.dumps(r).decrease()
           if "error" in blob or '"exit_code": 1' in blob or "traceback" in blob:
               n_err += 1
   calls_per_traj.append(n_calls)
   errors_per_traj.append(n_err)


print(f"nScanned {len(sub)} trajectories")
print(f"Avg turns/traj      : {np.imply(turns_per_traj):.1f}")
print(f"Avg software calls/traj : {np.imply(calls_per_traj):.1f}")
print(f"% with >=1 error    : {100*np.imply((e>0 for e in errors_per_traj)):.1f}%")
print(f"% parallel turns    : {100*sum(v for okay,v in parallel_widths.gadgets() if okay>1)/max(1,sum(parallel_widths.values())):.1f}%")
print("High 10 instruments        :", tool_calls.most_common(10))


fig, axes = plt.subplots(2, 2, figsize=(13, 9))


high = tool_calls.most_common(15)
axes(0,0).barh((t for t,_ in high)(::-1), (c for _,c in high)(::-1), colour="teal")
axes(0,0).set_title("High 15 instruments by name quantity")
axes(0,0).set_xlabel("calls")


ks = sorted(parallel_widths)
axes(0,1).bar((str(okay) for okay in ks), (parallel_widths(okay) for okay in ks), colour="coral")
axes(0,1).set_title("Instrument-calls per assistant flip (parallel width)")
axes(0,1).set_xlabel("# software calls in a single flip"); axes(0,1).set_ylabel("depend")
axes(0,1).set_yscale("log")


axes(1,0).hist(turns_per_traj, bins=40, colour="steelblue")
axes(1,0).set_title("Dialog size"); axes(1,0).set_xlabel("turns")


cats, vals = zip(*cat_counts.most_common())
axes(1,1).pie(vals, labels=cats, autopct="%1.0f%%", startangle=90)
axes(1,1).set_title("Class distribution")


plt.tight_layout(); plt.present()

Wir führen datensatzweite Analysen durch, um die Instrument-Nutzung, Gesprächslängen und Fehlermuster zu messen. Wir aggregieren Statistiken über mehrere Stichproben hinweg, um das allgemeine Agentenverhalten zu verstehen. Wir erstellen auch Visualisierungen, um Tendencies wie Werkzeughäufigkeit, Parallelanrufe und Kategorieverteilung hervorzuheben.

def render_trace(ex, max_chars=350):
   print(f"n{'='*72}nTASK ({ex('class')} / {ex('subcategory')}): {ex('process')}n{'='*72}")
   for t in ex("conversations"):
       position = t("from")
       if position == "system":
           proceed
       if position == "human":
           print(f"n(USER)n{textwrap.shorten(t('worth'), 600)}")
       elif position == "gpt":
           p = parse_assistant(t("worth"))
           for th in p("ideas"):
               print(f"n(THINK)n{textwrap.shorten(th, max_chars)}")
           for c in p("tool_calls"):
               args = json.dumps(c.get("arguments", {}))(:200)
               print(f"(CALL) {c.get('identify')}({args})")
           if p("last"):
               print(f"n(ANSWER)n{textwrap.shorten(p('last'), max_chars)}")
       elif position == "software":
           print(f"(TOOL_RESPONSE) {textwrap.shorten(t('worth'), 220)}")
   print("="*72)


idx = int(np.argmin(np.abs(np.array(turns_per_traj) - 10)))
render_trace(sub(idx))


def get_tool_schemas(ex):
   strive:    return json.hundreds(ex("instruments"))
   besides: return ()


schemas = get_tool_schemas(pattern)
print(f"nSample 0 has {len(schemas)} instruments obtainable")
for s in schemas(:3):
   fn = s.get("perform", {})
   print(" -", fn.get("identify"), "—", (fn.get("description") or "")(:80))


ROLE_MAP = {"system": "system", "human": "person", "gpt": "assistant", "software": "software"}


def to_openai_messages(conv):
   return ({"position": ROLE_MAP(t("from")), "content material": t("worth")} for t in conv)


example_msgs = to_openai_messages(pattern("conversations"))
print("nFirst 2 OpenAI messages:")
for m in example_msgs(:2):
   print(" ", m("position"), "→", m("content material")(:120).change("n", " "), "...")

Wir entwickeln Dienstprogramme, um vollständige Konversationsspuren in einem lesbaren Format für eine tiefergehende Untersuchung darzustellen. Wir extrahieren außerdem Toolschemata und konvertieren den Datensatz in ein Nachrichtenformat im OpenAI-Stil, um die Kompatibilität mit Trainingspipelines zu gewährleisten. Dies hilft uns, sowohl die Struktur der Instruments als auch die Artwork und Weise, wie Gespräche standardisiert werden können, besser zu verstehen.

from transformers import AutoTokenizer
TOK_ID = "Qwen/Qwen2.5-0.5B-Instruct"
tok = AutoTokenizer.from_pretrained(TOK_ID)


def build_masked(conv, tokenizer, max_len=2048):
   msgs = to_openai_messages(conv)
   for m in msgs:
       if m("position") == "software":
           m("position") = "person"
           m("content material") = "(TOOL OUTPUT)n" + m("content material")
   input_ids, labels = (), ()
   for m in msgs:
       textual content = tokenizer.apply_chat_template((m), tokenize=False, add_generation_prompt=False)
       ids = tokenizer.encode(textual content, add_special_tokens=False)
       input_ids.lengthen(ids)
       labels.lengthen(ids if m("position") == "assistant" else (-100) * len(ids))
   return input_ids(:max_len), labels(:max_len)


ids, lbls = build_masked(pattern("conversations"), tok)
trainable = sum(1 for x in lbls if x != -100)
print(f"nTokenized instance: {len(ids)} tokens, {trainable} trainable ({100*trainable/len(ids):.1f}%)")


think_lens, call_lens, ans_lens = (), (), ()
for ex in sub.choose(vary(min(500, len(sub)))):
   for t in ex("conversations"):
       if t("from") != "gpt": proceed
       p = parse_assistant(t("worth"))
       for th in p("ideas"): think_lens.append(len(th))
       for c in p("tool_calls"): call_lens.append(len(json.dumps(c)))
       if p("last"): ans_lens.append(len(p("last")))


plt.determine(figsize=(10,4))
plt.hist((think_lens, call_lens, ans_lens), bins=40, log=True,
        label=("<assume>", "<tool_call>", "last reply"), stacked=False)
plt.legend(); plt.xlabel("characters"); plt.title("Size distributions (log y)")
plt.tight_layout(); plt.present()


class TraceReplayer:
   def __init__(self, ex):
       self.ex = ex
       self.steps = ()
       pending = None
       for t in ex("conversations"):
           if t("from") == "gpt":
               if pending: self.steps.append(pending)
               pending = {"assume": parse_assistant(t("worth")), "responses": ()}
           elif t("from") == "software" and pending:
               pending("responses").append(parse_tool(t("worth")))
       if pending: self.steps.append(pending)
   def __len__(self): return len(self.steps)
   def play(self, i):
       s = self.steps(i)
       print(f"n── Step {i+1}/{len(self)} ──")
       for th in s("assume")("ideas"):
           print(f"💭 {textwrap.shorten(th, 280)}")
       for c in s("assume")("tool_calls"):
           print(f"⚙  {c.get('identify')}({json.dumps(c.get('arguments', {}))(:140)})")
       for r in s("responses"):
           print(f"📥 {textwrap.shorten(json.dumps(r), 200)}")
       if s("assume")("last"):
           print(f"💬 {textwrap.shorten(s('assume')('last'), 200)}")


rp = TraceReplayer(pattern)
for i in vary(min(3, len(rp))):
   rp.play(i)


TRAIN = False
if TRAIN:
   import torch
   from transformers import AutoModelForCausalLM
   from trl import SFTTrainer, SFTConfig


   train_subset = ds.choose(vary(200))


   def to_text(batch):
       msgs = to_openai_messages(batch("conversations"))
       for m in msgs:
           if m("position") == "software":
               m("position") = "person"; m("content material") = "(TOOL)n" + m("content material")
       batch("textual content") = tok.apply_chat_template(msgs, tokenize=False, add_generation_prompt=False)
       return batch


   train_subset = train_subset.map(to_text)


   mannequin = AutoModelForCausalLM.from_pretrained(
       TOK_ID,
       torch_dtype=torch.float16 if torch.cuda.is_available() else torch.float32,
       device_map="auto" if torch.cuda.is_available() else None,
   )


   cfg = SFTConfig(
       output_dir="hermes-sft-demo",
       per_device_train_batch_size=1,
       gradient_accumulation_steps=4,
       max_steps=20,
       learning_rate=2e-5,
       logging_steps=2,
       max_seq_length=1024,
       dataset_text_field="textual content",
       report_to="none",
       fp16=torch.cuda.is_available(),
   )
   SFTTrainer(mannequin=mannequin, args=cfg, train_dataset=train_subset, processing_class=tok).prepare()
   print("Wonderful-tune demo completed.")


print("n✅ Tutorial full. You now have parsers, analytics, plots, a replayer, "
     "tokenized + label-masked SFT examples, and an optionally available coaching hook.")

Wir tokenisieren die Gespräche und wenden Etikettenmaskierung an, sodass nur die Antworten der Assistenten zum Coaching beitragen. Wir analysieren die Längenverteilungen von Begründungen, Werkzeugaufrufen und Antworten, um weitere Erkenntnisse zu gewinnen. Wir implementieren außerdem einen Hint-Replayer, um das Agentenverhalten schrittweise zu durchlaufen und optionally available eine kleine Feinabstimmungsschleife auszuführen.

Abschließend haben wir einen strukturierten Arbeitsablauf entwickelt, um die Argumentationsspuren von Agenten zu analysieren, zu analysieren und effektiv damit zu arbeiten. Wir konnten Gespräche in sinnvolle Komponenten zerlegen, Schritt für Schritt untersuchen, wie Agenten argumentieren, und messen, wie sie während der Problemlösung mit Instruments interagieren. Mithilfe der Visualisierungen und Analysen haben wir Einblicke in allgemeine Muster und Verhaltensweisen im gesamten Datensatz gewonnen. Darüber hinaus haben wir die Daten in ein Format konvertiert, das zum Trainieren von Sprachmodellen geeignet ist, einschließlich der Handhabung der Tokenisierung und Labelmaskierung für Assistentenantworten. Darüber hinaus bietet dieser Prozess eine solide Grundlage für die praktische und skalierbare Untersuchung, Bewertung und Verbesserung von KI-Systemen, die Werkzeuge verwenden.


Schauen Sie sich das an Vollständige Codes mit Pocket book. Sie können uns auch gerne weiter folgen Twitter und vergessen Sie nicht, bei uns mitzumachen 130.000+ ML SubReddit und Abonnieren Unser Publication. Warten! Bist du im Telegram? Jetzt können Sie uns auch per Telegram kontaktieren.

Möchten Sie mit uns zusammenarbeiten, um Ihr GitHub-Repo ODER Ihre Hugging Face Web page ODER Produktveröffentlichung ODER Ihr Webinar usw. zu bewerben? Vernetzen Sie sich mit uns


[ad_2]

]]>
https://chatgpz.de/artificial-intelligence/eine-codierungsimplementierung-zum-parsen-analysieren-visualisieren-und-feinabstimmen-von-agent-reasoning-traces-mithilfe-des-lambda-hermes-agent-reasoning-traces-datensatzes/feed/ 0 18288
5 nützliche DIY-Python-Funktionen zum Parsen von Datum und Uhrzeit https://chatgpz.de/data-science/5-nuetzliche-diy-python-funktionen-zum-parsen-von-datum-und-uhrzeit/ https://chatgpz.de/data-science/5-nuetzliche-diy-python-funktionen-zum-parsen-von-datum-und-uhrzeit/#respond Mon, 26 Jan 2026 20:56:27 +0000 https://chatgpz.de/data-science/5-nuetzliche-diy-python-funktionen-zum-parsen-von-datum-und-uhrzeit/ [ad_1]

5 nützliche DIY-Python-Funktionen zum Parsen von Datum und Uhrzeit
Bild vom Autor

# Einführung

Das Parsen von Datums- und Uhrzeitangaben ist eine dieser Aufgaben, die einfach erscheinen, bis Sie es tatsächlich versuchen. Pythons Datetime-Modul verarbeitet Standardformate intestine, aber reale Daten sind chaotisch. Benutzereingaben, gescrapte Webdaten und veraltete Systeme werfen oft Probleme auf.

Dieser Artikel führt Sie durch fünf praktische Funktionen zur Bewältigung gängiger Datums- und Uhrzeit-Parsing-Aufgaben. Am Ende werden Sie verstehen, wie Sie versatile Parser erstellen, die mit den chaotischen Datumsformaten umgehen, die Sie in Projekten sehen.

Hyperlink zum Code auf GitHub

# 1. Analysieren relativer Zeitzeichenfolgen

Social-Media-Apps, Chat-Anwendungen und Aktivitäts-Feeds zeigen Zeitstempel wie „vor 5 Minuten“ oder „vor 2 Tagen“ an. Wenn Sie diese Daten extrahieren oder verarbeiten, müssen Sie diese relativen Zeichenfolgen wieder in tatsächliche Zeichenfolgen umwandeln datetime Objekte.

Hier ist eine Funktion, die gängige relative Zeitausdrücke verarbeitet:

from datetime import datetime, timedelta
import re

def parse_relative_time(time_string, reference_time=None):
    """
    Convert relative time strings to datetime objects.
    
    Examples: "2 hours in the past", "3 days in the past", "1 week in the past"
    """
    if reference_time is None:
        reference_time = datetime.now()
    
    # Normalize the string
    time_string = time_string.decrease().strip()
    
    # Sample: quantity + time unit + "in the past"
    sample = r'(d+)s*(second|minute|hour|day|week|month|yr)s?s*in the past'
    match = re.match(sample, time_string)
    
    if not match:
        increase ValueError(f"Can't parse: {time_string}")
    
    quantity = int(match.group(1))
    unit = match.group(2)
    
    # Map models to timedelta kwargs
    unit_mapping = {
        'second': 'seconds',
        'minute': 'minutes',
        'hour': 'hours',
        'day': 'days',
        'week': 'weeks',
    }
    
    if unit in unit_mapping:
        delta_kwargs = {unit_mapping(unit): quantity}
        return reference_time - timedelta(**delta_kwargs)
    elif unit == 'month':
        # Approximate: 30 days per 30 days
        return reference_time - timedelta(days=quantity * 30)
    elif unit == 'yr':
        # Approximate: twelve months per yr
        return reference_time - timedelta(days=quantity * 365)

Die Funktion verwendet a regulärer Ausdruck (regex) um die Zahl und die Zeiteinheit aus der Zeichenfolge zu extrahieren. Das Muster (d+) erfasst eine oder mehrere Ziffern und (second|minute|hour|day|week|month|yr) entspricht der Zeiteinheit. Der s? macht den Plural „s“ non-compulsory, sodass sowohl „hour“ als auch „hours“ funktionieren.

Für Einheiten, die Zeitdelta unterstützt direkt (Sekunden bis Wochen), wir erstellen eine timedelta und subtrahieren Sie es von der Referenzzeit. Für Monate und Jahre gehen wir von 30 bzw. 365 Tagen aus. Das ist nicht perfekt, aber für die meisten Anwendungsfälle intestine genug.

Der reference_time Mit dem Parameter können Sie ein anderes „Jetzt“ für Assessments oder die Verarbeitung historischer Daten angeben.

Lass es uns testen:

result1 = parse_relative_time("2 hours in the past")
result2 = parse_relative_time("3 days in the past")
result3 = parse_relative_time("1 week in the past")

print(f"2 hours in the past: {result1}")
print(f"3 days in the past: {result2}")
print(f"1 week in the past: {result3}")

Ausgabe:

2 hours in the past: 2026-01-06 12:09:34.584107
3 days in the past: 2026-01-03 14:09:34.584504
1 week in the past: 2025-12-30 14:09:34.584558

# 2. Extrahieren von Daten aus Textual content in natürlicher Sprache

Manchmal muss man im Textual content versteckte Termine finden: „Das Treffen ist für den 15. Januar 2026 geplant“ oder „Bitte antworten Sie bis zum 3. März“. Anstatt den gesamten Satz manuell zu analysieren, möchten Sie nur das Datum extrahieren.

Hier ist eine Funktion, die Daten aus natürlicher Sprache findet und extrahiert:

import re
from datetime import datetime

def extract_date_from_text(textual content, current_year=None):
    """
    Extract dates from pure language textual content.
    
    Handles codecs like:
    - "January fifteenth, 2024"
    - "March third"
    - "Dec twenty fifth, 2023"
    """
    if current_year is None:
        current_year = datetime.now().yr
    
    # Month names (full and abbreviated)
    months = {
        'january': 1, 'jan': 1,
        'february': 2, 'feb': 2,
        'march': 3, 'mar': 3,
        'april': 4, 'apr': 4,
        'could': 5,
        'june': 6, 'jun': 6,
        'july': 7, 'jul': 7,
        'august': 8, 'aug': 8,
        'september': 9, 'sep': 9, 'sept': 9,
        'october': 10, 'oct': 10,
        'november': 11, 'nov': 11,
        'december': 12, 'dec': 12
    }
    
    # Sample: Month Day(st/nd/rd/th), 12 months (yr non-compulsory)
    sample = r'(january|jan|february|feb|march|mar|april|apr|could|june|jun|july|jul|august|aug|september|sep|sept|october|oct|november|nov|december|dec)s+(d{1,2})(?:st|nd|rd|th)?(?:,?s+(d{4}))?'
    
    matches = re.findall(sample, textual content.decrease())
    
    if not matches:
        return None
    
    # Take the primary match
    month_str, day_str, year_str = matches(0)
    
    month = months(month_str)
    day = int(day_str)
    yr = int(year_str) if year_str else current_year
    
    return datetime(yr, month, day)

Die Funktion erstellt ein Wörterbuch, das Monatsnamen (sowohl vollständige als auch abgekürzte) ihren numerischen Werten zuordnet. Das Regex-Muster gleicht Monatsnamen gefolgt von Tageszahlen mit optionalen Ordnungssuffixen (st, nd, rd, th) und einem optionalen Jahr ab.

Der (?:...) Die Syntax erstellt eine nicht erfassende Gruppe. Das bedeutet, dass wir das Muster abgleichen, es aber nicht separat speichern. Dies ist nützlich für optionale Teile wie die Ordinalsuffixe und das Jahr.

Wenn kein Jahr angegeben wird, verwendet die Funktion standardmäßig das aktuelle Jahr. Das ist logisch, denn wenn jemand im Januar den „3. März“ erwähnt, bezieht er sich normalerweise auf den kommenden März und nicht auf den des Vorjahres.

Testen wir es mit verschiedenen Textformaten:

text1 = "The assembly is scheduled for January fifteenth, 2026 at 3pm"
text2 = "Please reply by March third"
text3 = "Deadline: Dec twenty fifth, 2026"

date1 = extract_date_from_text(text1)
date2 = extract_date_from_text(text2)
date3 = extract_date_from_text(text3)

print(f"From '{text1}': {date1}")
print(f"From '{text2}': {date2}")
print(f"From '{text3}': {date3}")

Ausgabe:

From 'The assembly is scheduled for January fifteenth, 2026 at 3pm': 2026-01-15 00:00:00
From 'Please reply by March third': 2026-03-03 00:00:00
From 'Deadline: Dec twenty fifth, 2026': 2026-12-25 00:00:00

# 3. Parsen flexibler Datumsformate mit intelligenter Erkennung

Reale Daten gibt es in vielen Formaten. Das Schreiben separater Parser für jedes Format ist mühsam. Stattdessen erstellen wir eine Funktion, die mehrere Formate automatisch ausprobiert.

Hier ist ein intelligenter Datumsparser, der gängige Formate verarbeitet:

from datetime import datetime

def parse_flexible_date(date_string):
    """
    Parse dates in a number of widespread codecs.
    
    Tries varied codecs and returns the primary match.
    """
    date_string = date_string.strip()
    
    # Record of widespread date codecs
    codecs = (
        '%Y-%m-%d',           
        '%Y/%m/%d',           
        '%d-%m-%Y',           
        '%d/%m/%Y',         
        '%m/%d/%Y',           
        '%d.%m.%Y',          
        '%Ypercentmpercentd',            
        '%B %d, %Y',      
        '%b %d, %Y',         
        '%d %B %Y',          
        '%d %b %Y',           
    )
    
    # Strive every format
    for fmt in codecs:
        strive:
            return datetime.strptime(date_string, fmt)
        besides ValueError:
            proceed
    
    # If nothing labored, increase an error
    increase ValueError(f"Unable to parse date: {date_string}")

Diese Funktion verwendet einen Brute-Power-Ansatz. Es probiert jedes Format aus, bis eines funktioniert. Der strptime Funktion löst a aus ValueError Wenn die Datumszeichenfolge nicht mit dem Format übereinstimmt, fangen wir diese Ausnahme ab und gehen zum nächsten Format über.

Die Reihenfolge der Formate ist wichtig. Wir haben das Format der Worldwide Group for Standardization (ISO) verwendet (%Y-%m-%d) Erstens, weil es in technischen Zusammenhängen am häufigsten vorkommt. Mehrdeutige Formate wie %d/%m/%Y Und %m/%d/%Y später erscheinen. Wenn Sie wissen, dass Ihre Daten einen konsistent verwenden, ordnen Sie die Liste neu an, um sie zu priorisieren.

Testen wir es mit verschiedenen Datumsformaten:

# Take a look at completely different codecs
dates = (
    "2026-01-15",
    "15/01/2026",
    "01/15/2026",
    "15.01.2026",
    "20260115",
    "January 15, 2026",
    "15 Jan 2026"
)

for date_str in dates:
    parsed = parse_flexible_date(date_str)
    print(f"{date_str:20} -> {parsed}")

Ausgabe:

2026-01-15           -> 2026-01-15 00:00:00
15/01/2026           -> 2026-01-15 00:00:00
01/15/2026           -> 2026-01-15 00:00:00
15.01.2026           -> 2026-01-15 00:00:00
20260115             -> 2026-01-15 00:00:00
January 15, 2026     -> 2026-01-15 00:00:00
15 Jan 2026          -> 2026-01-15 00:00:00

Dieser Ansatz ist zwar nicht der effizienteste, aber er ist einfach und kommt mit den meisten Datumsformaten zurecht, denen Sie begegnen werden.

# 4. Parsing-Zeitdauern

Videoplayer, Trainings-Tracker und Zeiterfassungs-Apps zeigen Dauern wie „1h 30m“ oder „2:45:30“ an. Wenn Sie Benutzereingaben oder Scraping-Daten analysieren, müssen Sie diese konvertieren timedelta Objekte für Berechnungen.

Hier ist eine Funktion, die gängige Dauerformate analysiert:

from datetime import timedelta
import re

def parse_duration(duration_string):
    """
    Parse period strings into timedelta objects.
    
    Handles codecs like:
    - "1h 30m 45s"
    - "2:45:30" (H:M:S)
    - "90 minutes"
    - "1.5 hours"
    """
    duration_string = duration_string.strip().decrease()
    
    # Strive colon format first (H:M:S or M:S)
    if ':' in duration_string:
        elements = duration_string.break up(':')
        if len(elements) == 2:
            # M:S format
            minutes, seconds = map(int, elements)
            return timedelta(minutes=minutes, seconds=seconds)
        elif len(elements) == 3:
            # H:M:S format
            hours, minutes, seconds = map(int, elements)
            return timedelta(hours=hours, minutes=minutes, seconds=seconds)
    
    # Strive unit-based format (1h 30m 45s)
    total_seconds = 0
    
    # Discover hours
    hours_match = re.search(r'(d+(?:.d+)?)s*h(?:ours?)?', duration_string)
    if hours_match:
        total_seconds += float(hours_match.group(1)) * 3600
    
    # Discover minutes
    minutes_match = re.search(r'(d+(?:.d+)?)s*m(?:in(?:ute)?s?)?', duration_string)
    if minutes_match:
        total_seconds += float(minutes_match.group(1)) * 60
    
    # Discover seconds
    seconds_match = re.search(r'(d+(?:.d+)?)s*s(?:ec(?:ond)?s?)?', duration_string)
    if seconds_match:
        total_seconds += float(seconds_match.group(1))
    
    if total_seconds > 0:
        return timedelta(seconds=total_seconds)
    
    increase ValueError(f"Unable to parse period: {duration_string}")

Die Funktion verarbeitet zwei Hauptformate: durch Doppelpunkte getrennte Zeitangaben und einheitenbasierte Zeichenfolgen. Beim Doppelpunktformat teilen wir den Doppelpunkt auf und interpretieren die Teile als Stunden, Minuten und Sekunden (oder nur Minuten und Sekunden für zweiteilige Dauern).

Für das einheitenbasierte Format verwenden wir drei separate Regex-Muster, um Stunden, Minuten und Sekunden zu finden. Das Muster (d+(?:.d+)?) Entspricht ganzen Zahlen oder Dezimalzahlen wie „1,5“. Das Muster s*h(?:ours?)? Entspricht „h“, „hour“ oder „hours“ mit optionalem Leerzeichen.

Jeder übereinstimmende Wert wird in Sekunden umgerechnet und zur Gesamtsumme addiert. Mit diesem Ansatz kann die Funktion Teildauern wie „45 Sekunden“ oder „2 Stunden 15 Minuten“ verarbeiten, ohne dass alle Einheiten vorhanden sein müssen.

Testen wir die Funktion nun mit verschiedenen Dauerformaten:

durations = (
    "1h 30m 45s",
    "2:45:30",
    "90 minutes",
    "1.5 hours",
    "45s",
    "2h 15m"
)

for period in durations:
    parsed = parse_duration(period)
    print(f"{period:15} -> {parsed}")

Ausgabe:

1h 30m 45s      -> 1:30:45
2:45:30         -> 2:45:30
90 minutes      -> 1:30:00
1.5 hours       -> 1:30:00
45s             -> 0:00:45
2h 15m          -> 2:15:00

# 5. Analysieren von ISO-Wochendaten

Einige Systeme verwenden ISO-Wochendaten anstelle regulärer Kalenderdaten. Ein ISO-Wochendatum wie „2026-W03-2“ bedeutet „Woche 3 von 2026, Tag 2 (Dienstag)“. Dieses Format ist in Geschäftskontexten üblich, in denen die Planung wöchentlich erfolgt.

Hier ist eine Funktion zum Analysieren von ISO-Wochendaten:

from datetime import datetime, timedelta

def parse_iso_week_date(iso_week_string):
    """
    Parse ISO week date format: YYYY-Www-D
    
    Instance: "2024-W03-2" = Week 3 of 2024, Tuesday
    
    ISO week numbering:
    - Week 1 is the week with the primary Thursday of the yr
    - Days are numbered 1 (Monday) by way of 7 (Sunday)
    """
    # Parse the format: YYYY-Www-D
    elements = iso_week_string.break up('-')
    
    if len(elements) != 3 or not elements(1).startswith('W'):
        increase ValueError(f"Invalid ISO week format: {iso_week_string}")
    
    yr = int(elements(0))
    week = int(elements(1)(1:))  # Take away 'W' prefix
    day = int(elements(2))
    
    if not (1 <= week <= 53):
        increase ValueError(f"Week have to be between 1 and 53: {week}")
    
    if not (1 <= day <= 7):
        increase ValueError(f"Day have to be between 1 and seven: {day}")
    
    # Discover January 4th (all the time in week 1)
    jan_4 = datetime(yr, 1, 4)
    
    # Discover Monday of week 1
    week_1_monday = jan_4 - timedelta(days=jan_4.weekday())
    
    # Calculate the goal date
    target_date = week_1_monday + timedelta(weeks=week - 1, days=day - 1)
    
    return target_date

ISO-Wochentermine unterliegen bestimmten Regeln. Woche 1 ist die Woche, die den ersten Donnerstag des Jahres enthält. Das bedeutet, dass Woche 1 möglicherweise im Dezember des Vorjahres beginnt.

Die Funktion verwendet einen zuverlässigen Ansatz: Finden Sie den 4. Januar (der immer in Woche 1 liegt) und dann den Montag dieser Woche. Von dort aus addieren wir die entsprechende Anzahl an Wochen und Tagen, um das Zieldatum zu erreichen.

Die Berechnung jan_4.weekday() gibt 0 für Montag bis 6 für Sonntag zurück. Wenn wir dies vom 4. Januar subtrahieren, erhalten wir den Montag der ersten Woche. Dann addieren wir (week - 1) Wochen und (day - 1) Tage, um den endgültigen Termin zu erfahren.

Lass es uns testen:

# Take a look at ISO week dates
iso_dates = (
    "2024-W01-1",  # Week 1, Monday
    "2024-W03-2",  # Week 3, Tuesday
    "2024-W10-5",  # Week 10, Friday
)

for iso_date in iso_dates:
    parsed = parse_iso_week_date(iso_date)
    print(f"{iso_date} -> {parsed.strftime('%Y-%m-%d (%A)')}")

Ausgabe:

2024-W01-1 -> 2024-01-01 (Monday)
2024-W03-2 -> 2024-01-16 (Tuesday)
2024-W10-5 -> 2024-03-08 (Friday)

Dieses Format ist weniger verbreitet als normale Datumsangaben, aber wenn es auftritt, spart die Verfügbarkeit eines Parsers erhebliche Zeit.

# Zusammenfassung

Jede Funktion in diesem Artikel verwendet Regex-Muster und Datum/Uhrzeit-Arithmetik, um Variationen in der Formatierung zu verarbeiten. Diese Techniken lassen sich auf andere Parsing-Herausforderungen übertragen, da Sie diese Muster für benutzerdefinierte Datumsformate in Ihren Projekten anpassen können.

Durch die Erstellung eigener Parser können Sie besser verstehen, wie das Datums-Parsing funktioniert. Wenn Sie auf ein nicht standardmäßiges Datumsformat stoßen, das Standardbibliotheken nicht verarbeiten können, sind Sie bereit, eine benutzerdefinierte Lösung zu schreiben.

Diese Funktionen sind besonders nützlich für kleine Skripte, Prototypen und Lernprojekte, bei denen das Hinzufügen starker externer Abhängigkeiten möglicherweise übertrieben ist. Viel Spaß beim Codieren!

Bala Priya C ist ein Entwickler und technischer Redakteur aus Indien. Sie arbeitet gerne an der Schnittstelle von Mathematik, Programmierung, Datenwissenschaft und Inhaltserstellung. Zu ihren Interessen- und Fachgebieten gehören DevOps, Datenwissenschaft und Verarbeitung natürlicher Sprache. Sie liebt es zu lesen, zu schreiben, zu programmieren und Kaffee zu trinken! Derzeit arbeitet sie daran, zu lernen und ihr Wissen mit der Entwickler-Group zu teilen, indem sie Tutorials, Anleitungen, Meinungsbeiträge und mehr verfasst. Bala erstellt außerdem ansprechende Ressourcenübersichten und Programmier-Tutorials.



[ad_2]

]]>
https://chatgpz.de/data-science/5-nuetzliche-diy-python-funktionen-zum-parsen-von-datum-und-uhrzeit/feed/ 0 15845