Python Pandas 滚动聚合一列列表
Posted
技术标签:
【中文标题】Python Pandas 滚动聚合一列列表【英文标题】:Python Pandas rolling aggregate a column of lists 【发布时间】:2019-07-06 03:30:35 【问题描述】:我有一个简单的数据框 df,其中有一列列表 lists
。我想根据lists
生成一个额外的列。
df
看起来像:
import pandas as pd
lists=1:[[1]],2:[[1,2,3]],3:[[2,9,7,9]],4:[[2,7,3,5]]
#create test dataframe
df=pd.DataFrame.from_dict(lists,orient='index')
df=df.rename(columns=0:'lists')
df
lists
1 [1]
2 [1, 2, 3]
3 [2, 9, 7, 9]
4 [2, 7, 3, 5]
我希望df
看起来像这样:
df
Out[9]:
lists rolllists
1 [1] [1]
2 [1, 2, 3] [1, 1, 2, 3]
3 [2, 9, 7, 9] [1, 2, 3, 2, 9, 7, 9]
4 [2, 7, 3, 5] [2, 9, 7, 9, 2, 7, 3, 5]
基本上我想对滚动的 2 个列表进行“总和”/append
。请注意第 1 行,因为我只有 1 个列表 1,所以 rolllists 就是那个列表。但在第 2 行,我有 2 个要附加的列表。然后对于第三行,附加df[2].lists
和df[3].lists
等。我以前做过类似的事情,参考这个:Pandas Dataframe, Column of lists, Create column of sets of cumulative lists, and record by record differences。
此外,如果我们可以在上面得到这部分,那么我想在groupby
中执行此操作(例如,下面的示例将是 1 组,例如,df
在groupby
中可能看起来像这样):
Group lists rolllists
1 A [1] [1]
2 A [1, 2, 3] [1, 1, 2, 3]
3 A [2, 9, 7, 9] [1, 2, 3, 2, 9, 7, 9]
4 A [2, 7, 3, 5] [2, 9, 7, 9, 2, 7, 3, 5]
5 B [1] [1]
6 B [1, 2, 3] [1, 1, 2, 3]
7 B [2, 9, 7, 9] [1, 2, 3, 2, 9, 7, 9]
8 B [2, 7, 3, 5] [2, 9, 7, 9, 2, 7, 3, 5]
我尝试了各种方法,例如 df.lists.rolling(2).sum(),但出现此错误:
TypeError: cannot handle this type -> object
在 Pandas 0.24.1 中,不幸的是在 Pandas 0.22.0 中,该命令不会出错,而是返回与 lists
中完全相同的值。所以看起来新版本的 Pandas 不能汇总列表?这是次要问题。
喜欢任何帮助!玩得开心!
【问题讨论】:
df.lists.cumsum()
可以处理列表,但它不会为您提供滚动窗口。像这样组合列表并不是 Pandas 的真正目的......
@JoshFriedlander,你能补充一些关于为什么 Pandas 不是为此而构建的细节吗?我发现它对许多类型的列/行数据操作很有用。有很多例子,您存储列表并希望以某种方式组合它们。 Pandas 是为数据操作和时间序列而构建的,数据帧可以保存列表、集合等。事实上 cumsum 可以做到这一点,如果 rolling 可以的话那就太好了。也许是一种取和减去两个偏移累积和的方法?
抱歉,这是不正确的,因为列表不是 Pandas 价值观的“一等公民”。请参阅 Jeff Reback 的评论 here。
我确实读过。不幸的是,因为列表非常 Pythonic,并且可以处理您需要将数字或字符串组作为一个整体处理的情况。必须有办法做到这一点。就算丑
哦,我确定有 a 方法。祝你好运!
【参考方案1】:
你可以从
开始import pandas as pd
mylists=1:[[1]],2:[[1,2,3]],3:[[2,9,7,9]],4:[[2,7,3,5]]
mydf=pd.DataFrame.from_dict(mylists,orient='index')
mydf=mydf.rename(columns=0:'lists')
mydf = pd.concat([mydf, mydf], axis=0, ignore_index=True)
mydf['group'] = ['A']*4 + ['B']*4
# initialize your new series
mydf['newseries'] = mydf['lists']
# define the function that appends lists overs rows
def append_row_lists(data):
for i in data.index:
try: data.loc[i+1, 'newseries'] = data.loc[i, 'lists'] + data.loc[i+1, 'lists']
except: pass
return data
# loop over your groups
for gp in mydf.group.unique():
condition = mydf.group == gp
mydf[condition] = append_row_lists(mydf[condition])
输出
lists Group newseries
0 [1] A [1]
1 [1, 2, 3] A [1, 1, 2, 3]
2 [2, 9, 7, 9] A [1, 2, 3, 2, 9, 7, 9]
3 [2, 7, 3, 5] A [2, 9, 7, 9, 2, 7, 3, 5]
4 [1] B [1]
5 [1, 2, 3] B [1, 1, 2, 3]
6 [2, 9, 7, 9] B [1, 2, 3, 2, 9, 7, 9]
7 [2, 7, 3, 5] B [2, 9, 7, 9, 2, 7, 3, 5]
【讨论】:
这行得通。所以如果我想“滚动”7 个周期,我需要继续在函数中添加。希望有一种方法可以通过变量简化它。我可以问为什么异常中的“通过”吗?您能预见例外情况或只是小心吗?或者是“第一种情况”的通行证,其中没有正确的列表数量可以组合?我现在对此表示赞同,看看是否还有其他事情发生。它有效,如果有更好的解决方案避开我们,我将选择正确答案... 了解try|except
,从函数中删除它们并更新函数。您将遇到来自pandas
的indexing
错误,因为最后一个indexer
不存在于数据框中。因此,如果发生 any 错误,只需 pass
【参考方案2】:
这个怎么样?
rolllists = [df.lists[1].copy()]
for row in df.iterrows():
index, values = row
if index > 1: # or > 0 if zero-indexed
rolllists.append(df.loc[index - 1, 'lists'] + values['lists'])
df['rolllists'] = rolllists
或者作为一个更可扩展的函数:
lists=1:[[1]],2:[[1,2,3]],3:[[2,9,7,9]],4:[[2,7,3,5]]
df=pd.DataFrame.from_dict(lists,orient='index')
df=df.rename(columns=0:'lists')
def rolling_lists(df, roll_period=2):
new_roll, rolllists = [], [df.lists[1].copy()] * (roll_period - 1)
for row in df.iterrows():
index, values = row
if index > roll_period - 1: # or -2 if zero-indexed
res = []
for i in range(index - roll_period, index):
res.append(df.loc[i + 1, 'lists']) # or i if 0-indexed
rolllists.append(res)
for li in rolllists:
while isinstance(li[0], list):
li = [item for sublist in li for item in sublist] # flatten nested list
new_roll.append(li)
df['rolllists'] = new_roll
return df
也很容易扩展到groupby
,只需将其包装在一个函数中并使用df.apply(rolling_lists)
。您可以提供任意数量的滚动行以用作roll_period
。希望这会有所帮助!
【讨论】:
这是否涉及滚动“周期”?我错过了什么吗?即 2 个周期滚动,还是 5 个?我认为这仅适用于 2。 编辑我的答案以扩展到n
roll_periods...检查一下
接下来我要试试这个。 @j。 doe 版本需要大量时间。
不幸的是,这个版本也花了相当长的时间。但工作如此赞成,但会给 J.Doe 接受的答案,因为 IMO 稍微容易一些。也就是说,对于我想要做的事情,我创建了一个解决方案,将列表转换为字符串,创建一个巨大的字符串作为卷,然后将该字符串转换回列表。无限快。例如,我的中型数据集的 J.Does 解决方案耗时 82 分钟。我的字符串返回列表花了 0.05 分钟...谢谢大家...以上是关于Python Pandas 滚动聚合一列列表的主要内容,如果未能解决你的问题,请参考以下文章