pandas - 如何使用正则表达式在 Pandas 数据框中选择一行和包含特定子字符串的行后面的固定行数

标签 pandas

问题 :
我有一个 Pandas 数据框,我试图从中提取特定的行。我感兴趣的行是那些包含日期的行,以及紧跟在带有日期的行之后的行。重要的是,我想将信息从日期后面的行移动到包含日期的行中的新列。通过这样做,我将在同一行上获得“一个人”的信息。明确地说,我想找到包含日期的行,并将信息从日期后面的行移动到新列中包含日期的行。
从这里:

    Col0  Col1       Col2      Col3   Col4    Col5
    0     NaN        NaN       NaN    NaN     NaN
    1     *1/23/20   Joe G     USA    NaN     G5 paper
    2     NaN        get_me    NaN    NaN     NaN
    3     +1/5/20    Frank F   CAN    NaN     F4 Paper
    4     NaN        get_me_2  NaN    NaN     NaN
对此:
    Col0  Col1     Col2     Col3   Col4     Col5      Col6(New column)
    0     1/23/20  Joe G     USA    NaN     G5 paper      get_me
    1     1/5/20  Frank F   CAN    NaN     F4 paper      get_me_2
换种说法 :我基本上只是想获取所有日期行以获取下一行的信息,因此对于每个日期都有一个人,然后他们的所有信息都在一行上。如果第二行中的所有信息都在其前一行的同一列中,则可以。
注意事项 :通常(但不总是)日期前有“*”或“+”字符(例如,**1/12/12 或 +5/5/20)。我首先尝试匹配包含日期的行。其中只有一个,但一个日期有一个名称“附加”(例如 *1/1/20Dev)。我想知道包含日期的列(日期总是在同一列中)是否有任何其他“废话”。这将是锦上添花,但这不是我遇到的核心问题。
第二行通常只有一个项目,但如果有更多,我可以稍后处理。我只需要同一行上的所有“人员”信息。我正在通过 PDF 读取原始数据,并试图对其进行清理。
我试过的 :我首先尝试匹配包含“类似日期”的字符串的字符串。实际上,这些都将在 Pandas 数据帧行中,但似乎正则表达式只适合获取包含日期的行(为此我可以立即获取该行并将其内容移动到包含日期的行上)
    import re
    search_in = '*1/4/13'
    wanted_regex = r'(\d+/\d+/\d+)'
    match = re.search(wanted_regex, search_in)
    match.group(1)
输出 :'1/4/13'
  • 摘要 :好的开始,但需要以某种方式迭代包含这些的每一行,并将信息从它后面的行移动到包含日期的行。

  • 一个很好的例子 :
        def regex_filter(myregex, val):
            if val:
                mo = re.search(myregex,val)
                if mo:
                    return True
                else:
                    return False
            else:
                return False
    
        df_filtered = 
        df[df['col'].apply(regex_filter)]
    
    是什么赋予了? 以上是我相信我正在尝试做的一个很好的例子,但我真的被难住了,我真的不知道我应该如何控制代码中的位置来获取下一行并将其向上移动。我看到很多类似的问题,但我无法确定是否应该分组、过滤、查询...?如果你能提供一个简短的理论,说明你为什么选择你选择的东西来解决这个问题,那么对于将来如何思考这个问题会非常有帮助。这就是我现在所处的位置,可以真正使用一些建议。谢谢你。

    最佳答案

    首先,从 pandas.Series.str.extract 开始获取类似日期的字符串:

    s = df["Col1"].str.extract("(\d+/\d+/\d+)", expand=False)
    
    然后使用 pandas.to_datetime实际过滤掉有效日期:
    s = pd.to_datetime(s, dayfirst=True, errors="coerce")
    # errors="coerce" to transform invalid strings
    
    到目前为止产生:
    0          NaT
    1   2020-01-23
    2          NaT
    3   2020-05-01
    4          NaT
    Name: Col1, dtype: datetime64[ns]
    
    然后使用 pandas.Series.ffilllimit==1获取有效日期和 右下一行 :
    df["Col1"] = s.ffill(limit=1)
    df = df.dropna(subset=["Col1"])
    print(df)
    
    所以我们有想要的行和他们的下一行:
       Col0       Col1      Col2 Col3  Col4      Col5
    1     1 2020-01-23     Joe G  USA   NaN  G5 paper
    2     2 2020-01-23    get_me  NaN   NaN       NaN
    3     3 2020-05-01   Frank F  CAN   NaN  F4 Paper
    4     4 2020-05-01  get_me_2  NaN   NaN       NaN
    
    最后,使用 pandas.DataFrame.groupby迭代和解开 Col2只要:
    dfs = []
    for k,d in df.groupby("Col1"):
        dfs.append(d.assign(tmp=["Col2", "Col6"]).pivot("Col1", "tmp", "Col2").merge(d))
    new_df = pd.concat(dfs).sort_index(1).reset_index(drop=True)
    
    print(new_df)
    
    最终输出:
            Col1     Col2 Col3  Col4      Col5      Col6
    0 2020-01-23    Joe G  USA   NaN  G5 paper    get_me
    1 2020-05-01  Frank F  CAN   NaN  F4 Paper  get_me_2
    
    groupby背后的逻辑部分:
  • groupby :为每个日期透视数据框的子集
  • d.assign(...) : 保持原来的 colname Col2并根据需要命名新列,Col6
  • pivot : 解开 Col2 .与 assignpivot ,子集看起来像:
      tmp            Col2      Col6
      Col1                         
      2020-05-01  Frank F  get_me_2 
    
  • 关于pandas - 如何使用正则表达式在 Pandas 数据框中选择一行和包含特定子字符串的行后面的固定行数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/65029838/

    相关文章:

    python-3.x - 如何通过 Python 上的循环将笛卡尔积保存到数据框?

    python - 我想向 Pandas 数据框添加一个新索引

    python - Pandas 将列集 reshape 为行

    python - 无法用 Beautiful Soup 解析 html 表

    python - 将Column1值转换为标题,将Column2值转换为pandas中的值

    python - 如何对一列使用透视/分组并连接其他列?

    python - 迭代 Pandas 中的行组

    python - 如何根据开始和结束时间将多个列值连接到 Pandas 数据框中的单个列

    python - Pandas 多索引 DataFrame 为每个索引添加子索引

    python-3.x - 使用fillna在Pandas中用列表填充空值