【问题标题】:faster way of creating pandas dataframe from another dataframe从另一个数据帧创建熊猫数据帧的更快方法
【发布时间】:2019-10-04 07:26:26
【问题描述】:

我有一个包含超过 41500 条记录和 3 个字段的数据框:IDstart_dateend_date

我想从中创建一个单独的数据框,其中只有 2 个字段:IDactive_years,其中将包含具有每个标识符的记录,这些记录针对存在于 start_year 和 end_year 范围之间的所有可能年份(包括 end范围内的年份)。

这就是我现在正在做的事情,但是对于 41500 行,它需要 2 个多小时才能完成。

df = pd.DataFrame(columns=['id', 'active_years'])
ix = 0

for _, row in raw_dataset.iterrows():

    st_yr = int(row['start_date'].split('-')[0]) # because dates are in the format yyyy-mm-dd
    end_yr = int(row['end_date'].split('-')[0])

    for year in range(st_yr, end_yr+1):

        df.loc[ix, 'id'] = row['ID']
        df.loc[ix, 'active_years'] = year
        ix = ix + 1

那么有没有更快的方法来实现这一点?

[EDIT] 一些尝试解决的示例,

raw_dataset = pd.DataFrame({'ID':['a121','b142','cd3'],'start_date':['2019-10-09','2017-02-06','2012-12-05'],'end_date':['2020-01-30','2019-08-23','2016-06-18']})

print(raw_dataset)
     ID  start_date    end_date
0  a121  2019-10-09  2020-01-30
1  b142  2017-02-06  2019-08-23
2   cd3  2012-12-05  2016-06-18

# the desired dataframe should look like this
print(desired_df)
     id  active_years
0  a121  2019
1  a121  2020
2  b142  2017
3  b142  2018
4  b142  2019
5   cd3  2012
6   cd3  2013
7   cd3  2014
8   cd3  2015
9   cd3  2016

【问题讨论】:

  • 您能与我们分享一下显示您的输入和所需输出的简约且可运行的示例吗?就这么简单:小样本输入和小样本输出数据。
  • @szerszen 我添加了一些示例来帮助您了解想法
  • 编写一个函数,从 start_date 和 end_date 列中提取年份,并将该函数提供给 .apply() 方法的调用。
  • 您的方法可能会创建一个数据框,其中的条目比您的原始条目更多(尽管字符串更短......) - 所以我会考虑将pd.to_datetime() 应用于您的列'start_date'/' end_date' - 然后您可以将年份检索为raw_dataset['start_date'][idx].year

标签: python pandas dataframe


【解决方案1】:

动态增长的 Python 列表比动态增长的 numpy 数组(这是 pandas 数据帧的底层数据结构)快得多。有关简要说明,请参阅here。考虑到这一点:

import pandas as pd

# Initialize input dataframe
raw_dataset = pd.DataFrame({
    'ID':['a121','b142','cd3'],
    'start_date':['2019-10-09','2017-02-06','2012-12-05'],
    'end_date':['2020-01-30','2019-08-23','2016-06-18'],
})

# Create integer columns for start year and end year
raw_dataset['start_year'] = pd.to_datetime(raw_dataset['start_date']).dt.year
raw_dataset['end_year'] = pd.to_datetime(raw_dataset['end_date']).dt.year

# Iterate over input dataframe rows and individual years
id_list = []
active_years_list = []
for row in raw_dataset.itertuples():
    for year in range(row.start_year, row.end_year+1):
        id_list.append(row.ID)
        active_years_list.append(year)

# Create result dataframe from lists
desired_df = pd.DataFrame({
    'id': id_list,
    'active_years': active_years_list,
})

print(desired_df)
# Output:
#     id  active_years
# 0  a121          2019
# 1  a121          2020
# 2  b142          2017
# 3  b142          2018
# 4  b142          2019
# 5   cd3          2012
# 6   cd3          2013
# 7   cd3          2014
# 8   cd3          2015
# 9   cd3          2016

【讨论】:

  • 这也是我的想法,但问题是:datetime 转换真的比简单的字符串拆分和转换为整数更快吗?
  • @MrFuppes 我没有检查获取整数开始/结束年份值的哪种方法最快。然而,我有理由确定这一步不是整体性能瓶颈。根据我的经验,性能瓶颈(使用具有大量行的数据帧时)将出现在创建结果数据帧的步骤中。
  • 对!关于这个问题,您对 Python 列表和 np 数组之间区别的注释实际上是我要说的重点。
猜你喜欢
  • 2018-12-25
  • 2018-01-05
  • 2021-12-02
  • 1970-01-01
  • 2018-08-18
  • 2020-05-12
  • 1970-01-01
  • 2019-10-29
  • 1970-01-01
相关资源
最近更新 更多