我有一个包含四列的数据框:名称,帐户,日期和点数
我需要按名称和帐户分组,然后用前几天的点数填写缺失的日期。
我知道该怎么做,但我不知道该怎么迅速做。我的实际数据帧是数以百万计的行。
这是问题的简化版本。我希望获得相同的输出,但是在填充大量数据时要使它快得多。
(实际数据来自Excel文件。)
import pandas as pd
data = """
name account date points
Steve e12 2014-02-07 17
Steve e12 2014-02-09 18
Steve g52 2014-02-03 52
Steve g52 2014-02-06 25
Steve g52 2014-02-08 31
Steve g52 2014-02-09 40
Fred g21 2014-02-02 17
Fred g21 2014-02-08 19
Fred g52 2014-02-07 21
Fred g52 2014-02-09 18
"""
dates = pd.date_range("2014-02-01", "2014-02-10")
def fill_in_dates(part_df):
part_df.index = pd.DatetimeIndex(part_df.date)
part_df = part_df.reindex(dates)
part_df = part_df.fillna(method='ffill')
return part_df
lines = [line.strip().split() for line in data.splitlines()[2:] if line.strip()]
columns = data.splitlines()[1].split()
df = pd.DataFrame(lines, columns=columns)
df = df.groupby(['name', 'account'], as_index=False).apply(fill_in_dates)
df = df.dropna()
df = df.reset_index()
df.date = df.level_1
df = df.drop(['level_0', 'level_1'], axis=1)
print(df)
这是输出:
name account date points
0 Fred g21 2014-02-02 17
1 Fred g21 2014-02-03 17
2 Fred g21 2014-02-04 17
3 Fred g21 2014-02-05 17
4 Fred g21 2014-02-06 17
5 Fred g21 2014-02-07 17
6 Fred g21 2014-02-08 19
7 Fred g21 2014-02-09 19
8 Fred g21 2014-02-10 19
9 Fred g52 2014-02-07 21
10 Fred g52 2014-02-08 21
11 Fred g52 2014-02-09 18
12 Fred g52 2014-02-10 18
13 Steve e12 2014-02-07 17
14 Steve e12 2014-02-08 17
15 Steve e12 2014-02-09 18
16 Steve e12 2014-02-10 18
17 Steve g52 2014-02-03 52
18 Steve g52 2014-02-04 52
19 Steve g52 2014-02-05 52
20 Steve g52 2014-02-06 25
21 Steve g52 2014-02-07 25
22 Steve g52 2014-02-08 31
23 Steve g52 2014-02-09 40
24 Steve g52 2014-02-10 40
答案 0 :(得分:1)
我认为您唯一的选择是在日期范围内拨打groupby
和reindex
:
def reindex(g):
return g.reindex(pd.date_range(g.index.min(), g.index.max()))
df['date'] = pd.to_datetime(df['date'], errors='coerce')
(df.set_index('date')
.groupby(['name', 'account'])
.points.apply(reindex)
.ffill()
.rename_axis(['name', 'account', 'date'])
.reset_index())
name account date points
0 Fred g21 2014-02-02 17
1 Fred g21 2014-02-03 17
2 Fred g21 2014-02-04 17
3 Fred g21 2014-02-05 17
4 Fred g21 2014-02-06 17
5 Fred g21 2014-02-07 17
6 Fred g21 2014-02-08 19
7 Fred g52 2014-02-07 21
8 Fred g52 2014-02-08 21
9 Fred g52 2014-02-09 18
10 Steve e12 2014-02-07 17
11 Steve e12 2014-02-08 17
12 Steve e12 2014-02-09 18
13 Steve g52 2014-02-03 52
14 Steve g52 2014-02-04 52
15 Steve g52 2014-02-05 52
16 Steve g52 2014-02-06 25
17 Steve g52 2014-02-07 25
18 Steve g52 2014-02-08 31
19 Steve g52 2014-02-09 40
答案 1 :(得分:0)
我认为您可以通过不为每个组执行part_df.index = pd.DatetimeIndex(part_df.date)
而是在整个数据帧级别上节省一些时间。然后,仅在“点”列上执行groupby
,并同时执行多个操作,而不是重新分配df
。整个操作如下:
df = pd.DataFrame(lines, columns=columns)
df = (df.set_index(pd.to_datetime(df.date))
.groupby(['name', 'account'])['points'].apply(lambda x: x.reindex(dates).ffill())
.dropna().reset_index().rename(columns={'level_2':'date'}))
,您将得到相同的结果。不确定大型数据集的改进幅度是多少,但是在示例中您给出的改进速度约为2.4倍。这可能取决于您拥有的组数和dates
答案 2 :(得分:0)
使用:
df.set_index('date')\
.groupby(['name','account'], as_index=False, group_keys=False)\
.apply(lambda x: x.reindex(pd.date_range(x.index.min(),
x.index.max(), freq='D'))
.ffill())\
.reset_index()
输出:
index name account points
0 2014-02-02 Fred g21 17
1 2014-02-03 Fred g21 17
2 2014-02-04 Fred g21 17
3 2014-02-05 Fred g21 17
4 2014-02-06 Fred g21 17
5 2014-02-07 Fred g21 17
6 2014-02-08 Fred g21 19
7 2014-02-07 Fred g52 21
8 2014-02-08 Fred g52 21
9 2014-02-09 Fred g52 18
10 2014-02-07 Steve e12 17
11 2014-02-08 Steve e12 17
12 2014-02-09 Steve e12 18
13 2014-02-03 Steve g52 52
14 2014-02-04 Steve g52 52
15 2014-02-05 Steve g52 52
16 2014-02-06 Steve g52 25
17 2014-02-07 Steve g52 25
18 2014-02-08 Steve g52 31
19 2014-02-09 Steve g52 40