Python pandas:合并列值if not None (join string),然后只保留第一行

Python pandas: merge column values if not None (join string), and then only keep first row

这里是有代表性的数据

asker1 = ['Peter', 'Markus', 'Rebecca', None, None, None, None, 'Sofie', 'Jesus', None]
que_text = ['QQQ', 'RRR', 'GGG', 'GGG', None, None, None, None, 'WWW', 'AAA']
date = ['14.10.2001', '12. October 1999', '14.10.2004', '14.10.2002', '14.10.2002', '14.10.2002', '14.10.2002', '14.10.2010', '14.10.2000', '14.10.2000']
identifier = ['Drs_2_00028_1', 'Drs_2_00029_1', 'Drs_2_00030_1_KlAnfr_000.tif', 'Drs_2_00030_1_KlAnfr_001.tif', 'Drs_2_00030_1_KlAnfr_002.tif', 'Drs_2_00030_1_KlAnfr_003.tif', 'Drs_2_00030_1_KlAnfr_004.tif', 'Drs_2_00052_1', 'Drs_2_00054_1_KlAnfr_000.tif', 'Drs_2_00054_1_KlAnfr_001.tif']
df2 = pd.DataFrame(
    list(zip(asker1, que_text, date, identifier)),
    columns =['asker1', 'que_text', 'date', 'identifier']
)

我正在从文件夹中的单个文件图片中提取文本信息。其中一些图片是连接的,这意味着它们代表后续页面(000=第一页;001=第二页)但并非所有图片都连接到另一个文件。

我在我的 pandas df2.

中读取了我想要的每个文件的信息作为一行

我的目标是每秒合并(001)/第三(002)/第四(003)/.. . que_text 值到其第一页(000)行('que_text'),只要该值不是 None。如果行(文件)连接到另一行(文件),'identifier' 列包含以下字符序列:_KlAnfr_\d{3}.tif

为什么只合并 que_text 值?由于我从正则表达式创建数据框,匹配原始字符串开头和结尾的某些单词,它们无法匹配每个 second/third/forth/... 页面,因为缺少正则表达式将捕获的唯一起始词(因为到目前为止我已经分别处理了每个文件。

例如第 9 行和第 10 行(均由标识符 col 连接):我想要一个字符串 'WWW AAA' (merged 'que_text[8]=WWW' and que_text[9]=AAA),以便尝试使用正则表达式进行匹配(再次) 随后

合并各自的 que_text 值后,除了第一行之外的所有行都应该被删除,即只有编号为 000 的行应该被保留。

示例的预期结果是:

    asker1 que_text              date                    identifier
0    Peter      QQQ        14.10.2001                 Drs_2_00028_1
1   Markus      RRR  12. October 1999                 Drs_2_00029_1
2  Rebecca  GGG GGG        14.10.2004  Drs_2_00030_1_KlAnfr_000.tif
3    Sofie     None        14.10.2010                 Drs_2_00052_1
4    Jesus  WWW AAA        14.10.2000  Drs_2_00054_1_KlAnfr_000.tif

这个

def merge_qts(sdf):
    sdf.que_text = " ".join(
        str(qt) for _, qt in sorted(zip(sdf.No, sdf.que_text))
        if qt is not None
    )
    return sdf

mask = df2.identifier.str.contains(r"_KlAnfr_\d{3}\.tif$")
df3 = df2.loc[mask, ["que_text", "identifier"]]
pattern = r"^(.*?_KlAnfr)_(\d{3}).tif$"
df3[["ID", "No"]] = df2.identifier.str.extract(pattern)
df2.loc[mask, "que_text"] = df3.groupby("ID").apply(merge_qts).que_text
df2 = df2[~df2.identifier.str.contains(r"_KlAnfr_\d{2}[1-9]\.tif$")].reset_index(drop=True)

结果

    asker1 que_text              date                    identifier
0    Peter      QQQ        14.10.2001                 Drs_2_00028_1
1   Markus      RRR  12. October 1999                 Drs_2_00029_1
2  Rebecca  GGG GGG        14.10.2004  Drs_2_00030_1_KlAnfr_000.tif
3    Sofie     None        14.10.2010                 Drs_2_00052_1
4    Jesus  WWW AAA        14.10.2000  Drs_2_00054_1_KlAnfr_000.tif

一些解释:

  • 第一步是构建 mask 并将需要处理的数据提取到 df3 中。
  • 然后通过从列 identifier 中提取标识分组 (-> ID) 和数字 (-> [=18) 的第一部分,将 2 列添加到 df3 =]).
  • 之后 groupby ID 列,合并 que_text 条目,并将 df2 中的原始 que_text 列替换为合并后的 que_text 列。
  • 最后删除所有 identifier 列的值与模式匹配但数字部分不是 '000'.
  • 的行

替代方法:

def merge_qts(sdf):
    if sdf.shape[0] > 1:
        sdf.que_text.iat[0] = " ".join(
            qt for _, qt in sorted(zip(sdf.No, sdf.que_text))
            if qt is not None
        )
    return sdf.iloc[0, :]

pattern = r"^(.*?_KlAnfr)_(\d{3}).tif$"
df2[["ID", "No"]] = df2.identifier.str.extract(pattern)
df2.ID[df2.ID.isna()] = range(df2.ID.isna().sum())
df2 = (
    df2.groupby("ID", as_index=False, sort=False)
       .apply(merge_qts)
       .drop(columns=["ID", "No"])
)