【问题标题】:How to optimize a function which contains for loops and 20 millions rows in dataframe如何优化包含 for 循环和数据框中 2000 万行的函数
【发布时间】:2020-09-24 05:36:50
【问题描述】:

我有一个 pandas 数据框 df,如下所示:

student_id   category_id  count
1              111        10
2              111        5
3              222        8
4              333        5
5              111        6

同样,我有 2000 万行。

我想计算每个 student_id 的评分。例如,让我们考虑一个 category_id “111”。我们在这个类别中有 3 个学生 ID 1、2 和 5。 student_id 1 有 10 个计数, student_id 2 有 5 个计数, student_id 5 有 6 个计数。 每个 student_id 对 category_id 的评分由以下公式计算:

(count per student_id / total number of counts per category_id) * 5 

对于 student_id 1 -> 10/ 21 * 5 = 2.38

对于 student_id 2 -> 5/ 21 *5 = 1.19

对于 student_id 5 -> 6/ 21 * 5 = 1.43

下面是我必须计算的函数:

countPerStudentID = datasetPandas.groupby('student_id').agg(list)
countPerCategoryID = datasetPandas.groupby('category_id').agg(list)

studentIDMap = dict()
def func1(student_id):
    if student_id in studentIDMap:
        return studentIDMap[student_id]
    runningSum = 0
    countList = countPerStudentID.loc[student_id, 'count']
    for count in countList:
        runningSum += count
    studentIDMap[student_id] = runningSum
    return studentIDMap[student_id]

#Similar to the above function
categoryIDMap = dict()
def func2(category_id):
    if category_id in categoryIDMap:
        return categoryIDMap[category_id]
    runningSum = 0
    countList = countPerCategoryID.loc[category_id, 'count']
    for count in countList:
        runningSum += count
    categoryIDMap[category_id] = runningSum
    return categoryIDMap[category_id]

最后我从下面调用这两个函数:

#Calculating rating category-wise
rating = []
for index, row in df.iterrows():

    totalCountPerCategoryID = func1(row['category_id'])
    totalCountPerStudentID = func2(row['student_id'])

    rating.append((totalCountPerStudentID / totalCountPerCategoryID) * 5)

df['rating'] = rating

需要的输出:

student_id   category_id  count   rating
1              111        10       2.38
2              111        5        1.19
3              222        8         5
4              333        5         5 
5              111        6        1.43

由于数据量很大,运行它需要大量时间。我想知道如何优化这个计算

提前致谢

【问题讨论】:

    标签: python pandas dataframe optimization bigdata


    【解决方案1】:

    天哪,不要使用iterrowsappend,更不用说一起。难怪你的表现在爬行。对于pandasiterrows 应该是最后的手段。

    您应该能够使用矢量化方法实现此目的:

    >>> df['rating'] = df['count'].div(df.groupby('category_id')['count'].transform(sum)).mul(5)
    >>> df
       student_id  category_id  count    rating
    0           1          111     10  2.380952
    1           2          111      5  1.190476
    2           3          222      8  5.000000
    3           4          333      5  5.000000
    4           5          111      6  1.428571
    

    【讨论】:

    • 非常感谢。这可以节省很多时间。此解决方案是否适用于大数据?当我尝试时,我收到此错误A value is trying to be set on a copy of a slice from a DataFrame. Try using .loc[row_indexer,col_indexer] = value instead,并且新列“评级”的值在 10^-5
    • 是的,矢量化方法在应用于大数据时大有帮助。关于您的问题,@QuangHoang 已经涵盖了它 - 您当前的 df 可能是原件的副本或切片。
    【解决方案2】:

    你不需要循环,这是groupby案例:

    df['rating'] = df['count']/df.groupby('category_id')['count'].transform('sum') * 5
    

    输出:

       student_id  category_id  count    rating
    0           1          111     10  2.380952
    1           2          111      5  1.190476
    2           3          222      8  5.000000
    3           4          333      5  5.000000
    4           5          111      6  1.428571
    

    【讨论】:

    • @QuangHoang 非常感谢。此解决方案是否适用于大数据?当我尝试时,我收到此错误A value is trying to be set on a copy of a slice from a DataFrame. Try using .loc[row_indexer,col_indexer] = value instead 并且新列“评级”的值在 10^-5
    • 这是一个不同的问题。你的df 是一些更大的数据框的一部分。将.copy() 添加到df 的定义中。同时搜索 SO 上的警告。
    • 谢谢。添加 .copy() 后错误消失了。不幸的是,我看到了 10^-6 和 10^-7 的评分值。当我尝试使用 5 行数据框时,它会产生奇迹。
    • 您的代码遵循的逻辑是加权平均值。当然,对于大型数据集,这是预期的。假设您有 10**6 个学生,每个学生计数 10。你的逻辑会给每个 5e-5。也许您应该将'sum' 替换为'max'
    猜你喜欢
    • 2016-02-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-25
    • 2020-06-26
    • 2013-11-15
    相关资源
    最近更新 更多