创建数据框 - 基于文本坐标的顺序

Dol*_*itz 1 python dataframe pandas python-tesseract

我有一个包含多列的数据框(我从pytesseract.image_to_data(img_pl,lang="eng", output_type='data.frame', config='--psm 11')[使用的 psm 11 或 12,相同的结果] 获取它并仅从中获取重要的列),让我们看看以下列:

# This is the data I get from the above command,
# I added it like that so you will be able to copy and test it
data = {'left': [154, 154, 200, 154, 201, 199],
        'top': [0, 3, 3, 7, 8, 12],
        'width': [576, 168, 162, 168, 155, 157],
        'height': [89, 10, 10, 10, 10, 10],
        'text': ['text1', 'text2', 'text3', 'text4', 'text5', 'text6']}
output_test_min_agg = pd.DataFrame(data)
# Output:
+----+---+-----+------+-------+
|left|top|width|height|   text|
+----+---+-----+------+-------+
| 154|  0|  576|    89|  text1|
| 154|  3|  168|    10|  text2|
| 200|  3|  162|    10|  text3|
| 154|  7|  168|    10|  text4|
| 201|  8|  155|    10|  text5|
| 199| 12|  157|    10|  text6|
+----+---+-----+------+-------+
Run Code Online (Sandbox Code Playgroud)

请注意,某些坐标偏离了几个像素(从我看到的最大偏离 3-5 个像素来看),这就是为什么宽度也可以考虑在内(例如“abc”和“abcdef”的左侧将是不同但宽度我们可以看到它达到了相同的尺寸

排除结果如下:

+-----+-------+-------+
|index| col 01| col 02|
+-----+-------+-------+
|    0|  text1|       |
|    1|  text2|  text3|
|    2|  text4|  text5|
|    3|       |  text6|
+-----+-------+-------+
Run Code Online (Sandbox Code Playgroud)

我得到的最好的结果是:

output_test_min_agg=output_test_min.sort_values('top', ascending=True)
output_test_min_agg = output_test_min_agg.groupby(['top', 'left'], sort=False)['text'].sum().unstack('left')
output_test_min_agg.reindex(sorted(output_test_min_agg.columns), axis=1).dropna(how='all')
Run Code Online (Sandbox Code Playgroud)

但这仍然不好,因为如果topleft甚至有 1 个像素的差异,它将为它们创建一个全新的列和行

我怎样才能完成这样的任务呢?

Lid*_*lef 5

我通过执行以下操作来完成它:

我为每个目的创建了 3 个函数

1)使用你的虚拟数据:

import pandas as pd
import numpy as np
# Create a dictionary of data for the DataFrame
data = {'left': [154, 154, 200, 154, 201, 199],
        'top': [0, 3, 3, 7, 8, 12],
        'width': [576, 168, 162, 168, 155, 157],
        'height': [89, 10, 10, 10, 10, 10],
        'text': ['text1', 'text2', 'text3', 'text4', 'text5', 'text6']}
# Create the DataFrame
df = pd.DataFrame(data)
Run Code Online (Sandbox Code Playgroud)

2)使用您提供的代码创建一个函数+添加对NaN值的处理

def optimizeDf(df: pd.DataFrame) -> pd.DataFrame:
    df['left+width'] = df['left'] + df['width']
    df = df.sort_values(by=['top'], ascending=True)
    df = df.groupby(['top', 'left+width'], sort=False)['text'].sum().unstack('left+width')
    df = df.reindex(sorted(df.columns), axis=1).dropna(how='all').dropna(axis='columns', how='all')
    df = df.fillna('')
    return df
df = optimize_df(df)
Run Code Online (Sandbox Code Playgroud)

3) 创建一个函数来根据名称阈值相似度合并列:

def mergeDfColumns(old_df: pd.DataFrame, threshold: int = 10) -> pd.DataFrame:
    new_columns = {}
    old_columns = old_df.columns
    i = 0
    while i < len(old_columns) - 1:
        if any(old_columns[i+1] == old_columns[i] + x for x in range(1, threshold)):
            new_col = old_df[old_columns[i]] + old_df[old_columns[i+1]]
            new_columns[old_columns[i+1]] = new_col
            i += 1
        else:
            new_columns[old_columns[i]] = old_df[old_columns[i]]
        i += 1
    new_columns[old_columns[i]] = old_df[old_columns[i]]
    return pd.DataFrame.from_dict(new_columns).replace('', np.nan).dropna(axis='columns', how='all').fillna('')
df = mergeDfColumns(df)
Run Code Online (Sandbox Code Playgroud)

4) 创建一个函数来根据名称阈值相似度合并行:

def mergeDfRows(old_df: pd.DataFrame, threshold: int = 2) -> pd.DataFrame:
    new_df = old_df.iloc[:1]
    for i in range(1, len(old_df)):
        if abs(old_df.index[i] - old_df.index[i - 1]) < threshold:
            new_df.iloc[-1] = new_df.iloc[-1] + old_df.iloc[i]
        else:
            new_df = new_df.append(old_df.iloc[i])
    return new_df.reset_index(drop=True)
df = mergeDfRows(df)
Run Code Online (Sandbox Code Playgroud)

最终结果如下:

+-+-----+-----+-----+
| |  322|  362|  730|
+-+-----+-----+-----+
|0|     |     |text1|
|1|text2|text3|     |
|2|text4|text5|     |
|3|     |text6|     |
+-+-----+-----+-----+   
Run Code Online (Sandbox Code Playgroud)

这是我从你的虚拟数据中得到的最好结果,但请注意如何text1获取它自己的行和列,这是因为如果你看一下数据,你会发现它的宽度和高度与其他数据相比很大,我的意思是我认为图像中的表格有某种与其非常接近的标题,并将pytesseract其识别为表格的一部分,我给您的建议是尝试一些其他config选项或使用一些深度学习来对表格进行分类更好的。