我有一组名称UniqueNames
和一个Pandas DataFrame NamesOverTime
,每行都有一个名称列表。我想获得一个系列,表明该名称是否包含在特定的行/日期。以下代码完美无缺,但似乎很慢。任何想法如何改善性能?
for index, row in UniqueNames.iterrows():
IndSeries = (NamesOverTime==row['Name']).any(axis=1)
一个例子可能是:
UniqueNames = DataFrame({'Name': ('hello1', 'hello2', 'hello3',
'hello4', 'ciao5')})
NamesOverTime = DataFrame( {'1': ('hello1', 'hello2', 'hello3', 'hello4'),
'2': ('hello1', 'hello2', 'hello3', NaN),
'3': ('hello3', 'hello1', 'ciao5', NaN)})
NamesOverTime = NamesOverTime.transpose()
NamesOverTime.index = pd.date_range('2015-05-31', periods=3, freq='M')
因此,数据框中的名称属于arbirtrary顺序。
我的实际数据集大小更大,但不是质量。我有一组大约4000个名称和一个Dataframe T = 300(行)和N = 3000(列)
编辑:预期输出是UniqueNames
中包含的每个名称的Pandas系列对象。我能用你的答案获得的最快速度是这样的,但它仍然是大约。比原始版本慢3倍。
NamesOTStack = NamesOverTime.stack()
NamesOTStack = NamesOTStack.reset_index(1)
for index, row in UniqueNames.iterrows():
temp = NamesOTStack[NamesOTStack.loc[:,0]==row['Name']]
IndSeries = pd.Series(NamesOverTime.index.isin(temp.index))
IndSeries.index = NamesOverTime.index
IndSeries
的{p> 'hello4'
如下所示:
IndSeries
Out[16]:
2015-05-31 True
2015-06-30 False
2015-07-31 False
Freq: M, dtype: bool
答案 0 :(得分:2)
编辑:您已经改变了输入的结构,这非常重要,并且需要不同的答案。无论如何,这里去了。我创建了一个数据框,其中有3000个名称从4000中随机选择,而不是每行365行中的替换。
name_time_pairs = NamesOverTime.unstack().dropna()
name_time_pairs.name = 'name'
name_time_pairs = name_time_pairs.reset_index().iloc[:, 1:]
name_time_pairs['value'] = True
In [104]: name_time_pairs[:2]
Out[104]:
time name value
0 2015-01-01 ypac True
1 2015-01-02 fjnq True
到目前为止,我们有一个DataFrame,每个时间对都有一行,一行包含True
,总共1,098,000行。现在需要做的就是转动表并用False
填充空值。
result = name_time_pairs.pivot(index='time', columns='name', values='value').fillna(False)
如果你可以证明这比循环浏览4000个名字要慢并且扫描每个循环中的原始数据框慢,我会吃掉我的帽子。我的速度提高了100倍。
你应该打破这个解决方案,看看每个步骤是如何工作的,因为它非常简洁,而且我已经花了太多时间来回答这个问题。它也很复杂,因为我认为结果的结构是不寻常的。基本上你拥有的是一组时间名称对。将这些作为布尔数据框的索引和列标签存储在我看来效率低下,也许可以用另一种方式完成。