【问题标题】:Improving Code Efficiency in Dataset Generation提高数据集生成中的代码效率
【发布时间】:2020-02-04 04:25:56
【问题描述】:

我正在尝试生成一个数据集,其中给定年份范围内的每一天都有固定数量的商店。反过来,每家商店都销售固定数量的产品。每个商店和每一天的特定产品都有销售价值 (£) 和售出的产品数量。

但是,运行这些 for 循环需要一段时间来创建数据集。

有没有什么办法可以提高我的代码效率?

# Generate one row Dataframes (for concatenation) for each product, in each store, on each date

dataframes = []
for d in datelist:
    for s in store_IDs:
        for p in product_IDs:
            products_sold = random.randint(1,101)
            sales = random.randint(100,1001)
            data_dict = {'Date': [d], 'Store ID': [s], 'Product ID': [p], 'Sales': [sales], 'Number of Products Sold': [products_sold]}
            dataframe = pd.DataFrame(data_dict) 
            dataframes.append(dataframe)

test_dataframe = pd.concat(dataframes)

【问题讨论】:

  • 你看下面我的回答了吗?

标签: python python-3.x performance for-loop


【解决方案1】:

您的代码现在真的很慢的主要原因是您的三重循环中隐藏了数据帧结构。这不是必需的。现在,您正在每个循环内创建一个新的数据框。以pandas 可以摄取的某种格式创建所有数据然后创建数据帧一次会更有效。

对于您拥有的结构,您可以做的最简单的 mod 是创建一个数据行列表,在您现在构建时为每一行附加一个新字典到该列表,然后从列表中创建一个 df字典... Pandas 知道如何做到这一点。我还删除了您在字典中拥有的项目的列表括号。没必要。

import pandas as pd
import random

datelist = [1, 2, 4, 55]
store_IDs = ['6A', '27B', '12C']
product_IDs = ['soap', 'gum']


data = []  # I just renamed this for clarity
for d in datelist:
    for s in store_IDs:
        for p in product_IDs:
            products_sold = random.randint(1,101)
            sales = random.randint(100,1001)
            data_dict = {'Date': d, 'Store ID': s, 'Product ID': p, 'Sales': sales, 'Number of Products Sold': products_sold}
            data.append(data_dict)  # this is building a list of dictionaries...

print(data[:3])

df = pd.DataFrame(data)
print(df.head())

产量:

[{'Date': 1, 'Store ID': '6A', 'Product ID': 'soap', 'Sales': 310, 'Number of Products Sold': 35}, {'Date': 1, 'Store ID': '6A', 'Product ID': 'gum', 'Sales': 149, 'Number of Products Sold': 34}, {'Date': 1, 'Store ID': '27B', 'Product ID': 'soap', 'Sales': 332, 'Number of Products Sold': 60}]

   Date Store ID Product ID  Sales  Number of Products Sold
0     1       6A       soap    310                       35
1     1       6A        gum    149                       34
2     1      27B       soap    332                       60
3     1      27B        gum    698                       21
4     1      12C       soap    658                       51
[Finished in 0.6s]

【讨论】:

  • 感谢您的帮助杰夫 H!我已经按照您的建议进行了调整。然而,它似乎仍然需要异常长的时间来生成。我认为主要问题之一可能是我必须生成的数据的时间段超过三年(每天)。我不认为可以使用可能有助于提高效率的地图功能?
  • 那么,让我们了解一下大小......完成后,您构建的数据框的大小是多少。这应该是 3 个列表大小的乘积,您可以通过 df.info() 确认。我可以在帖子中添加关于如何将循环折叠成列表理解的帖子,但我很好奇你现在有什么表现,因为这可能不会是一个白天和一天的变化。当前的执行时间是多少?
  • 大小约为 3 年半(以天为单位)= 1277 乘以 99 家商店 = 126,423 乘以 8999 产品 = 1,137,680,577 行。目前,循环还没有完成迭代......
  • 是的,这实在太大了,不实用。我建议您备份并弄清楚您的目的是什么。如果您尝试对如此简单的事物进行建模或模拟,则不需要这么多数据,尤其是因为您是从均匀分布中绘制的。所有汇总统计数据都可以在没有任何数据的情况下通过分析确定。如果您正在建模某些东西并想要这种类型的信息,您可以在需要时“即时”生成它。如果你真的想创建这么大的东西,那么下一步是数据库。
【解决方案2】:

你知道你的尺寸很大吗?

大小约为 3 年半(以天为单位)= 1277 乘以 99 家商店 = 126,423 乘以 8999 产品 = 1,137,680,577 行。

如果您平均需要 16 个字节(这已经不多),那么您至少需要 17GB 的内存!

出于这个原因,Store_IDsProduct_IDs 应该只是小整数,例如在更具描述性名称的表中的索引。

提高效率的方法是减少函数调用!例如。您可以使用numpy随机数生成批量生成随机值。

假设所涉及的所有数字都可以放入 16 位,这里有一个解决您的问题的方法(仍然需要大量内存):

import pandas as pd
import numpy as np

def gen_data(datelist, store_IDs, product_IDs):
    date16 = np.arange(len(datelist), dtype=np.int16)
    store16 = np.arange(len(store_IDs), dtype=np.int16)
    product16 = np.arange(len(product_IDs), dtype=np.int16)
    A = np.array(np.meshgrid(date16, store16, product16), dtype=np.int16).reshape(3,-1)
    length = A.shape[1]
    sales = np.random.randint(100, 1001, size=(1,length), dtype=np.int16)
    sold = np.random.randint(1, 101, size=(1,length), dtype=np.int16)
    data = np.concatenate((A,sales,sold), axis=0)
    df = pd.DataFrame(data.T, columns=['Date index', 'Store ID index', 'Product ID index', 'Sales', 'Number of Products Sold'], dtype=np.int16)
    return df

我获得的机器上的 FWIW:

            Date  Store ID  Product ID  Sales  Number of Products Sold
0              0         0           0    127                       85
1              0         0           1    292                       37
2              0         0           2    180                       36
3              0         0           3    558                       88
4              0         0           4    519                       79
...          ...       ...         ...    ...                      ...
1137680572  1276        98        8994    932                       78
1137680573  1276        98        8995    401                       47
1137680574  1276        98        8996    840                       77
1137680575  1276        98        8997    717                       91
1137680576  1276        98        8998    632                       24

[1137680577 rows x 5 columns]

real    1m16.325s
user    0m22.086s
sys 0m25.800s

(我没有足够的内存并使用交换)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-12-23
    • 2017-04-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-10-27
    • 2012-04-26
    • 1970-01-01
    相关资源
    最近更新 更多