Python:快速子集和循环数据框

Posted

技术标签:

【中文标题】Python:快速子集和循环数据框【英文标题】:Python: fast subsetting and looping dataframe 【发布时间】:2016-10-12 20:37:02 【问题描述】:

我有以下太慢的最小代码。对于我需要的 1000 行,大约需要 2 分钟。我需要它跑得更快。

import numpy as np
import pandas as pd

df = pd.DataFrame(np.random.randint(0,1000,size=(1000, 4)), columns=list('ABCD'))
start_algorithm = time.time()
myunique = df['D'].unique()
for i in myunique:
    itemp = df[df['D'] == i]
    for j in myunique:
        jtemp = df[df['D'] == j]

我知道 numpy 可以使它运行得更快,但请记住,我想保留原始数据帧(或 numpy 中的数组)的一部分以用于列“D”的特定值。如何提高其性能?

【问题讨论】:

在提问时尽量提供Minimal, Complete, and Verifiable example。如果有 pandas 问题,请提供示例 inputoutput 数据集(CSV/dict/JSON/Python 代码格式的 5-7 行 作为文本,因此可以在为您编写答案时使用它)。这将有助于避免以下情况your code isn't working for meit doesn't work with my data 等。 不清楚你想做什么...... itempjtemp 有什么区别?正如 MaxU 所说,样本代表性输入数据和预期输出以及如何实现的解释将有很大帮助。 目前还不清楚你要做什么!您有无论如何都没有连接的嵌套循环 - 为什么需要它们?你 100% 确定你需要循环吗?如果我运行您的代码,我会从df 两次获得同一行 - 在itempjtemp 中。因此,如果不清楚地了解您的目标,几乎不可能为您提供帮助 那么很容易回答你的问题——如果你想加快你的代码,摆脱循环。这是您一般问题的一般答案... ;) 【参考方案1】:

避免多次计算子数据帧df[df['D'] == i]。原始代码计算这个len(myunique)**2 次。相反,您可以为每个i 计算一次(即总共len(myunique) 次),存储结果,然后稍后将它们配对。例如,

    groups = [grp for di, grp in df.groupby('D')]
    for itemp, jtemp in IT.product(groups, repeat=2):
        pass

import pandas as pd
import itertools as IT
df = pd.DataFrame(np.random.randint(0,1000,size=(1000, 4)), columns=list('ABCD'))

def using_orig():
    myunique = df['D'].unique()
    for i in myunique:
        itemp = df[df['D'] == i]
        for j in myunique:
            jtemp = df[df['D'] == j]

def using_groupby():
    groups = [grp for di, grp in df.groupby('D')]
    for itemp, jtemp in IT.product(groups, repeat=2):
        pass

In [28]: %timeit using_groupby()
10 loops, best of 3: 63.8 ms per loop
In [31]: %timeit using_orig()
1 loop, best of 3: 2min 22s per loop

关于评论:

我可以轻松地将 itemp 和 jtemp 替换为 a=1 或打印“Hello”,所以忽略它

上面的答案解决了如何更有效地计算itempjtemp。如果itempjtemp 不是您实际计算的核心,那么我们需要更好地了解您真正想要计算的内容,以便建议(如果可能)更快地计算它的方法.

【讨论】:

我对 itemp 和 jtemp 的评论是为了强调(正如我当时所想的那样)问题在于独特性。正如我现在从 unutbu 的惊人回答中看到的那样,我显然错了,我向 *** 的其他成员道歉,因为有些误导他们。您的回答很好,我感谢大家的时间和贡献。【参考方案2】:

这是基于"D" 列中的唯一元素形成组的矢量化方法 -

# Sort the dataframe based on the sorted indices of column 'D'
df_sorted = df.iloc[df['D'].argsort()]

# In the sorted dataframe's 'D' column find the shift/cut indces 
# (places where elements change values, indicating change of groups). 
# Cut the dataframe at those indices for the final groups with NumPy Split.
cut_idx = np.where(np.diff(df_sorted['D'])>0)[0]+1
df_split = np.split(df_sorted,cut_idx)

样本测试

1] 使用随机元素形成示例数据框:

>>> df = pd.DataFrame(np.random.randint(0,100,size=(5, 4)), columns=list('ABCD'))
>>> df
    A   B   C   D
0  68  68  90  39
1  53  99  20  85
2  64  76  21  19
3  90  91  32  36
4  24   9  89  19

2] 运行原代码并打印结果:

>>> myunique = df['D'].unique()
>>> for i in myunique:
...     itemp = df[df['D'] == i]
...     print itemp
... 
    A   B   C   D
0  68  68  90  39
    A   B   C   D
1  53  99  20  85
    A   B   C   D
2  64  76  21  19
4  24   9  89  19
    A   B   C   D
3  90  91  32  36

3] 运行建议的代码并打印结果:

>>> df_sorted = df.iloc[df['D'].argsort()]
>>> cut_idx = np.where(np.diff(df_sorted['D'])>0)[0]+1
>>> df_split = np.split(df_sorted,cut_idx)
>>> for split in df_split:
...     print split
... 
    A   B   C   D
2  64  76  21  19
4  24   9  89  19
    A   B   C   D
3  90  91  32  36
    A   B   C   D
0  68  68  90  39
    A   B   C   D
1  53  99  20  85

【讨论】:

以上是关于Python:快速子集和循环数据框的主要内容,如果未能解决你的问题,请参考以下文章

Python 中 Pandas 的快速子集化

python&pandas:列表中具有值的子集数据框[重复]

循环子集,获取文件并将结果保存在数据框中

For循环子集化的熊猫数据框

从循环 if 语句子集熊猫时间序列数据帧

如何使用for循环或条件在pandas数据框的子集中创建多个回归模型(statsmodel)?