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)
但这仍然不好,因为如果top或left甚至有 1 个像素的差异,它将为它们创建一个全新的列和行
我怎样才能完成这样的任务呢?
我通过执行以下操作来完成它:
我为每个目的创建了 3 个函数
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)
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)
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)
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选项或使用一些深度学习来对表格进行分类更好的。