#🔒 Link to line characteristic possibilities: How can I improve the architecture of a decision tree?

7 messages · Page 1 of 1 (latest)

inland glacier
#

Context: Developing a program that uses pymupdf to inspect PDF files -> analyze & categorize lines by their position relative to the margin, indentation, position in paragraph, region of the page, density (characters per line), font name, and font size -> TXT format

Currently, the program runs through what's essentially a giant decision tree to collect or skip a line. Not every combination of the factors above are considered. For example, a sparse (density) line at the header (region) of the page is skipped, regardless of its font name and size. I've been reading about design patterns, but I'm not sure what to implement instead of its current structure (which is making debugging + expanding very difficult). I've been considering chain of responsibility, but it doesn't seem like it's a 100% fit. One major drawback is that analysis isn't as simple as yes/no i.e. it's not linear. Suppose the first class acts on line density. However, density alone is never enough to collect/skip a line. So, now it needs to pass the line to a class that acts on the region of the page. Here, only header is skipped. If it's in the footer, it could be the end of a paragraph or it could be a page number. So, now it needs to rely on position in paragraph........... The following class I've added an example of a document I analyzed and a sample of line characteristics + decisions (from 216 combinations).

Should I still move to chain of responsibility, or something else? An alternative I've seen could be a giant decision table (inspired by the picture attached), but it doesn't seem like a popular choice from what I've read (and would also mean up to 1728 combinations if I'm strict).

Link to line characteristic possibilities and snippet of filtering: https://paste.pythondiscord.com/W6SA

Thank you

tall valeBOT
#

@inland glacier

Python help channel opened

Remember to:

  • Ask your Python question, not if you can ask or if there's an expert who can help.
  • Show a code sample as text (rather than a screenshot) and the error message, if you've got one.
  • Explain what you expect to happen and what actually happens.

:warning: Do not pip install anything that isn't related to your question, especially if asked to over DMs.

still scroll
#

what you’re building is actually a rule-based classification engine, not a linear filter.
that’s why Chain of Responsibility feels wrong — because your logic is multi-dimensional, not sequential.
instead of a decision tree, i recommend this method :

  1. represent each line as a feature object
  2. each rule becomes a small evaluator
  3. combine them using a scoring engine
inland glacier
# still scroll what you’re building is actually a rule-based classification engine, not a linea...

Yeah, you're right about that, and thank you for your help! I think I've already implemented #1 if I'm understanding what you mean by feature object

@dataclass
class LineContext:
    line_group: list
    position_in_paragraph: PositionInParagraph
    indentation: LineIndentation
    region: VerticalRegion
    margin_position: MarginPosition
    density: Density
    font_name: FontName
    font_size: FontSize

    @classmethod
    def create(cls, layout, line_group, groups_iter, result):
        return cls(
            line_group=line_group,
            position_in_paragraph=layout.get_position_in_paragraph(line_group, groups_iter, result),
            indentation=layout.get_line_indentation(line_group, groups_iter, result),
            region=layout.get_line_region(line_group),
            margin_position=layout.get_line_position(line_group),
            density=layout.get_line_density(line_group),
            font_name=layout.get_font_name(line_group),
            font_size=layout.get_font_size(line_group)
        )

Could you please further elaborate on #2 and #3, though? I'm not sure I'm quite understanding what you mean by evaluators and a scoring engine

tall valeBOT
#
Python help channel closed for inactivity

This help channel has been closed. Feel free to create a new post in #1035199133436354600. To maximize your chances of getting a response, check out this guide on asking good questions.