【问题标题】:Pandas transpose raw data with inconsistent row patternPandas 转置行模式不一致的原始数据
【发布时间】:2023-02-10 11:45:07
【问题描述】:

我有以下原始数据导出:

import pandas as pd
df = pd.DataFrame({ 
     'Data': ['A15','abc','A25',50,'abc','A30',20,'def','A4','hijk','A',10,'mnop'],

    })
df

我正在尝试将此原始数据转置为包含 3 列的表:Name, Number and Text

每次 A 出现时我都想要一行,因为这是一致的模式。在那之后总是有一个文本,但只是有时有一个数字。如果出现此号码,它始终是A 之后的直接行。我的预期输出是这样的:

关于我如何解决这个问题的任何想法?非常感谢!

【问题讨论】:

    标签: python pandas


    【解决方案1】:
    import re
    import pandas as pd
    import numpy as np
    
    df = pd.DataFrame({'Data': ['A15', 'abc', 'A25', 50, 'abc', 'A30', 20, 'def', 'A4', 'hijk', 'A', 10, 'mnop']})
    

    转换为列表:

    flat_list = df['Data'].tolist()
    

    迭代列表,如果元素匹配 Ad+ 添加新子列表,否则附加到最后一个子列表:

    nested_list = []
    while len(flat_list) > 0:
        element = flat_list.pop(0)
        if re.fullmatch("Ad*", str(element)):
            nested_list.append([element])
        else:
            nested_list[-1].append(element)
    

    如果子列表只有两项,则列出 'Number' 为 np.NaN 的字典:

    as_records = [
        {'Name': l[0], 'Number': l[1], 'text': l[2]} if len(l) == 3 else {'Name': l[0], 'Number': np.NaN, 'text': l[1]} 
        for l in nested_list]
    

    转换为数据帧:

    df_out = pd.DataFrame(as_records)
    

    哪个返回:

      Name  Number  text
    0  A15     NaN   abc
    1  A25    50.0   abc
    2  A30    20.0   def
    3   A4     NaN  hijk
    4    A    10.0  mnop
    

    【讨论】:

    • 感谢您的回复!我收到以下错误:IndexError: list index out of range 出现在行中:nested_list[-1].append(element)。当我调试我的element = A1. 01:05
    • 似乎 Name 中的某些元素不遵循格式 "Ad*"。您可以使用 if re.match("Ad*", str(element)):,这样元素就不必完全匹配“A+optional number”模式。但是您应该知道,任何以 A 开头的文本也会产生一个新行。
    • 根据问题的严重程度,您可以推进模式以匹配“A”、“A+digit”或出现的任何其他模式,例如您显示的模式:“A+digit+dot+space+timestamp” '.
    • 谢谢!我只需要将它更改为re.match 就可以了!非常感激
    【解决方案2】:

    您可以定义掩码并使用 pivot

    m1 = df['Data'].str.startswith('A')
    m2 = m1.isna() #OR: pd.to_numeric(df['Data'], errors='coerce').notna()
    m1 = m1.fillna(False)
    
    df2 = (df
     .assign(index=m1.cumsum(),
             col=np.select([m1, m2], ['Name', 'Number'], 'Text')
            )
     .pivot(index='index', columns='col', values='Data')
    )
    

    输出:

    col   Name Number  Text
    index                  
    1      A15    NaN   abc
    2      A25     50   abc
    3      A30     20   def
    4       A4    NaN  hijk
    5        A     10  mnop
    

    中间体:

        Data     m1  m1(v2)     m2  m1(cumsum)
    0    A15   True    True  False           1
    1    abc  False   False  False           1
    2    A25   True    True  False           2
    3     50    NaN   False   True           2
    4    abc  False   False  False           2
    5    A30   True    True  False           3
    6     20    NaN   False   True           3
    7    def  False   False  False           3
    8     A4   True    True  False           4
    9   hijk  False   False  False           4
    10     A   True    True  False           5
    11    10    NaN   False   True           5
    12  mnop  False   False  False           5
    

    【讨论】:

    • 感谢您的回复!我得到一个 ValueError: Index contains duplicate entries, cannot reshape,我猜这是因为我有 A 具有相同名称的行?
    • @SOK 这意味着您并不总是拥有名称数字文本模式,但有时名称之间有多个数字/文本。在这种情况下,使用 pivot_table 代替 pivot 并选择用作聚合的内容(例如 aggfunc='first' 仅保留第一个条目)
    • 谢谢!是的,没错,有时它只是Name, Text,有时它是Name, Number, Text。如果我使用aggfunc='first',那么它只会删除Number列,保留Text,但将数字插入Text
    • 奇怪,它不应该这样做。你能提供一个更新的例子吗?
    • 我不太确定如何导出原始数据,但该列(作为列表)看起来像这样:['A1. 01:08', 'text 1', 'A1. 01:12', '6 - Smith', 'ABCDEFG', 'A1. 01:13', '38 - Johnson', 'HIGKLMNO']。我猜是因为在这种情况下数字可能实际上是文本?
    【解决方案3】:
    def function1(dd:pd.DataFrame):
        ss1=dd.loc[df.Data.astype(str).str.isdigit(),"Data"]
        ss2=pd.Index(dd.iloc[1:].Data).difference(ss1)
        return pd.Series({"Name":dd.head(1).squeeze(),"Number":ss1.max(),"text":ss2.max()},name=dd.name)
    
    col1=df.Data.astype(str).str.contains("A").cumsum()-1
    df.groupby(col1).apply(function1)
    

    出去

      Name  Number  text
    Data                   
    0     A15     NaN   abc
    1     A25    50.0   abc
    2     A30    20.0   def
    3      A4     NaN  hijk
    4       A    10.0  mnop
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-03-31
      • 2015-05-15
      • 1970-01-01
      • 1970-01-01
      • 2021-11-24
      • 1970-01-01
      • 1970-01-01
      • 2015-08-13
      相关资源
      最近更新 更多