【问题标题】:Create dataframe from rows under a row with a certain condition从具有特定条件的行下的行创建数据框
【发布时间】:2021-06-28 04:35:45
【问题描述】:

我有一个丑陋的数据源,我正在尝试清理它。我不能使源更清洁,我是这样接收的。我正在使用 Python 和 Pandas 数据框。第一列包含一个带有日期时间对象的单元格,然后是几个带有字符串的单元格,然后是另一个日期时间对象,然后是更多字符串。字符串的数量未知。

我想将每组数据放入自己的数据框中,以便我可以将每组整齐地导出到电子表格中的单独工作表中,这是该项目所必需的。

所以,输入数据框的第一列是这样的:

df[col1]
-----
datetime.datetime.strptime('06/23/2021', "%m/%d/%Y")
'tony'
'nikki'
'james'
datetime.datetime.strptime('06/24/2021', "%m/%d/%Y")
'amy'
'jose'
datetime.datetime.strptime('06/25/2021', "%m/%d/%Y")
'tony'
'jose'
'eddie'
'anna'

我想把它分成几个这样的数据框:

df1[col1]
-----
'tony'
'nikki'
'james'

df2[col1]
-----
'amy'
'jose'

df3[col1]
-----
'tony'
'jose'
'eddie'
'anna'

我不知道该怎么做,而不仅仅是遍历行,我知道这是使用 pandas 时的最后手段。

遍历行就像(这是伪代码,因为这是我努力的一部分)

strRows = []
dfs = []
for index,row in df.iterrows():
    
    while row not contain datetime object:
        # append row to list to add to new dataframe
        strRows.append(row)
    # create new dataFrame with saved rows
    newDF = pd.DataFrame(strRows)
    dfs.append(newDF)
    

    

虽然最终我想保留日期信息并在该日期之后命名新数据框,但现在我只关心提取行。

我的问题:df.iterrows() 是解决这个问题的好方法,还是有一种优先的非迭代方法?

感谢任何建议。谢谢。

编辑:

根据这里的建议和更一般的搅动,我最终以这种方式创建了一个包含日期本身的新列。

df["Day"] = pd.to_datetime(df['Col1'], errors='coerce').fillna(method='ffill')

errors='coerce' 在解析“NaT”结果时出错,fillna(method='ffill') 使日期填满整个列。这一点很重要,特别是因为 Col1 包含日期时间和字符串,所以当to_datetime 遇到字符串时,我希望它给出NaT,以便fillna 可以使用ffill 来填写日期时间.

然后,由于我的最终目标实际上是在电子表格中创建工作表,而不是单独的数据框,因此我使用由 groupby 创建的字典直接写入我的 xlsx。

df_days = {key: value for (key, value) in df.groupby('Day')}

with writer as writer:
    for key in df_days:
        df_days[key].to_excel(writer, key, index=False)

【问题讨论】:

    标签: python pandas dataframe


    【解决方案1】:

    我确定我最近看到了一个类似的案例,但找不到它。可能有更好的解决方案,但这里有一个选项可以创建一个新列,该列累积一个计数器,您可以使用@987654321 来拆分数据@:

    import pandas as pd
    import datetime
    
    # make a test df
    data = [datetime.datetime.strptime('06/23/2021', "%m/%d/%Y"),
    'tony',
    'nikki',
    ...]
    
    df = pd.DataFrame({"raw":data})
    
    # basically count +1 every time a datetime object is encountered
    df["groups"] = df.raw.apply(isinstance, args=(datetime.datetime,)).astype(int).cumsum()
    
    

    结果:

                        raw  groups
    0   2021-06-23 00:00:00       1
    1                  tony       1
    2                 nikki       1
    3                 james       1
    4   2021-06-24 00:00:00       2
    5                   amy       2
    6                  jose       2
    7   2021-06-25 00:00:00       3
    8                  tony       3
    9                  jose       3
    10                eddie       3
    11                 anna       3
    

    然后您可以通过df.groupby("groups")获取各个组。

    【讨论】:

      【解决方案2】:

      使用 datar 很容易做到这一点,由 pandas 提供支持,但实现了类似 dplyr 的语法:

      >>> import datetime
      >>> from datar.all import (
      ...     f, tibble, grepl, cumsum, tail,
      ...     select, mutate, group_modify, group_split, group_by, 
      ... )
      >>> 
      >>> df = tibble(
      ...     col1=[
      ...         datetime.datetime.strptime('06/23/2021', "%m/%d/%Y"),
      ...         'tony',
      ...         'nikki',
      ...         'james',
      ...         datetime.datetime.strptime('06/24/2021', "%m/%d/%Y"),
      ...         'amy',
      ...         'jose',
      ...         datetime.datetime.strptime('06/25/2021', "%m/%d/%Y"),
      ...         'tony',
      ...         'jose',
      ...         'eddie',
      ...         'anna',
      ...     ]
      ... )
      >>> df
                         col1
                     <object>
      0   2021-06-23 00:00:00
      1                  tony
      2                 nikki
      3                 james
      4   2021-06-24 00:00:00
      5                   amy
      6                  jose
      7   2021-06-25 00:00:00
      8                  tony
      9                  jose
      10                eddie
      11                 anna
      
      >>> dfs = df >> mutate(
      ...     # or your way to identify the datetime value
      ...     is_date=grepl("00:00:00", f.col1),
      ...     # group the datetime and the following values
      ...     group=cumsum(f.is_date)
      ... ) >> group_by(
      ...     f.group
      ... ) >> select(
      ...     # don't include the intermediate column
      ...     ~f.is_date
      ... ) >> group_modify(
      ...     # exclude the first row
      ...     lambda df: tail(df, -1)
      ... ) >> group_split()
      >>> # dfs is a generator
      >>> list(dfs)
      [    group     col1
        <int64> <object>
      0       1     tony
      1       1    nikki
      2       1    james,     group     col1
        <int64> <object>
      3       2      amy
      4       2     jose,     group     col1
        <int64> <object>
      5       3     tony
      6       3     jose
      7       3    eddie
      8       3     anna]
      
      >>> _[0] # take a look at the first df
          group     col1
        <int64> <object>
      0       1     tony
      1       1    nikki
      2       1    james
      

      免责声明:我是datar 包的作者。

      【讨论】:

        【解决方案3】:

        这里假设datetime.datetime.strptime... 是一个字符串:

        df['col2'] = df['col1'].str.extract(r"datetime.datetime.strptime\('(.*)', .*").ffill()
        df = df[~df['col1'].str.contains('datetime')]
        
               col1        col2
        1    'tony'  06/23/2021
        2   'nikki'  06/23/2021
        3   'james'  06/23/2021
        5     'amy'  06/24/2021
        6    'jose'  06/24/2021
        8    'tony'  06/25/2021
        9    'jose'  06/25/2021
        10  'eddie'  06/25/2021
        11   'anna'  06/25/2021
        

        然后使用df.groupby('col2') 进行进一步处理,利用'col2' 为每个组命名您的dataframe

        【讨论】:

          猜你喜欢
          • 2017-11-26
          • 2022-09-28
          • 2023-03-07
          • 1970-01-01
          • 2019-05-24
          • 1970-01-01
          • 2019-04-07
          • 1970-01-01
          • 2021-07-26
          相关资源
          最近更新 更多