<p>在过去的数据帧迭代中,我也遇到过类似的问题-<a href="https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.iterrows.html" rel="nofollow noreferrer">^{<cd1>}</a>乍一看似乎是正确的选择,因为它易于使用,但是它的方便是有代价的。这里的<a href="https://medium.com/@rtjeannier/pandas-101-cont-9d061cb73bfc" rel="nofollow noreferrer">a helpful blog</a>概述了pandas中的方法,以提高迭代效率。你知道吗</p>
<p>结果是-不要使用<code>iterrows</code>。一般来说,可以使用索引作为迭代器,然后使用<code>df.loc</code>或<code>df.iloc</code>访问数据帧的行,如下所示:</p>
<pre><code>for i in df.index:
print(df.loc[i, :])
</code></pre>
<h2>使用<code>df.apply</code></h2>
<p><code>apply</code>方法允许您将用户定义的函数应用于数据帧的所有列或行。虽然这里的用法可能有些不直观,但它是迄今为止最快的:</p>
<pre><code>import numpy as np
import pandas as pd
def counter(row):
if np.any(row[row > 0]):
return np.sum(row[row > 0])
else:
return 0
N = 100000
df = pd.DataFrame({'A': np.random.randint(0, 2, N),
'B': np.random.randint(0, 2, N),
'C': np.random.randint(0, 2, N),
'D': np.random.randint(0, 2, N)})
df['match-count'] = df.apply(counter, axis=1, raw=True)
</code></pre>
<p>这里,函数将检查数据帧的每一行(由<code>axis=1</code>指定);<code>np.any</code>返回<code>True</code>如果布尔选择<code>row[row > 0]</code>不是空的,此时布尔选择用<code>np.sum</code>减少以获得最终计数。我们将<code>raw</code>关键字参数设置为<code>True</code>,以便传递原始的<code>numpy</code>数组,该数组应用于减少操作(如sum)以提高性能(请参见<a href="https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.apply.html" rel="nofollow noreferrer">docs</a>)。你知道吗</p>
<p>在我的机器上运行大约需要1.2秒。你知道吗</p>
<h2>编辑</h2>
<p>Gio的回答显示了一个原则,我认为这是使用pandas时的一个很好的实践——如果存在可以直接对数据帧进行操作的方法(例如<code>sum</code>,<code>cumsum</code>),那么尝试使用这些方法,因为它们总是会更快。你知道吗</p>
<p>在这样的方法不存在的地方,<code>df.apply</code>如果指定要应用的更复杂的操作,那么它会很有用-这只是未来的一个提示!你知道吗</p>
<h2>编辑II</h2>
<p>上面带有apply的示例假设dataframe中的所有列都用于布尔选择。如果只有特定列具有需要用于计数器的数值,请在<code>counter</code>方法中使用Gio的建议:</p>
<pre><code>def counter(row):
selection = row[['in_deeds', 'in_valuation', 'in_property', 'in_sg']] > 0
if np.any(selection):
return np.sum(selection)
else:
return 0
</code></pre>