pandas 根据文本坐标创建 Dataframe 顺序

gab6jxml  于 2023-02-02  发布在  其他
关注(0)|答案(1)|浏览(129)
    • bounty将在5天后过期**。回答此问题可获得+50声望奖励。Dolev Miz希望引起更多人对此问题的关注:我得到了很多意见和评论,但仍然没有答案,请帮助我解决这个问题

我有一个包含多个列的数据框(我从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|
+----+---+-----+------+-------+

请注意,有些坐标偏离了几个像素(从我看到的最大值3 - 5个像素偏离),这就是为什么宽度也可以考虑在内(例如,"abc"和"abcdef"的左侧将不同,但我们可以看到宽度达到相同的大小
例外结果如下:

+-----+-------+-------+
|index| col 01| col 02|
+-----+-------+-------+
|    0|  text1|       |
|    1|  text2|  text3|
|    2|  text4|  text5|
|    3|       |  text6|
+-----+-------+-------+

我得到的最好结果是这样的:

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')

但这仍然不好,因为如果topleft有1个像素差,它将为它们创建一个全新的列和行
我怎样才能完成这样的任务呢?

ssgvzors

ssgvzors1#

我通过以下操作实现了这一点:
我为每个目的做了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)
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)
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)
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)
最终结果如下:
+-+-----+-----+-----+
| |  322|  362|  730|
+-+-----+-----+-----+
|0|     |     |text1|
|1|text2|text3|     |
|2|text4|text5|     |
|3|     |text6|     |
+-+-----+-----+-----+

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

相关问题