【问题标题】:For loop alternative for multiple columns within a function (pandas)For循环替代函数中的多个列(熊猫)
【发布时间】:2018-12-30 14:39:43
【问题描述】:

想象一个像下面这样的函数:

def func(df, cols, col_ref):

    for c in cols:    
        df[c] = df.apply(lambda row: row[c] * ref[(ref.SOURCE == row[col_ref])].VALUE.item() ,axis=1)
    return df

调用该函数时,参数为

  1. 具有多列 (df) 的数据框
  2. 一列或多列(列)
  3. 参考列,其中当前行的值指示使用了其他数据帧 (ref) 的哪一行

我可以调用函数,例如像这样:

df_new = func(df, ['col1','col2','col3'], 'ref_value')

或者像这样:

df_new2 = func(df, 'col4', 'ref_value')

是否有替代 for 循环的方法?我的数据框很大,使用 for 循环执行此操作最多需要一个小时。

重要的是,该函数仍然能够处理一列以及多列作为第二个参数。

编辑

一个简单的例子:

df
+-----+------+------+------+------+-----------+
| No  | col1 | col2 | col3 | col4 | ref_value |
+-----+------+------+------+------+-----------+
| 523 |   34 |  593 |  100 |   10 | A1        |
| 523 |  100 |  100 |  100 |   43 | A1        |
| 523 | 1867 |   15 |  632 |   64 | B2        |
| 732 |  100 |  943 |  375 |  325 | B1        |
| 732 | 1000 |  656 |  235 |   63 | B1        |
+-----+------+------+------+------+-----------+

ref
+--------+-------+
| SOURCE | VALUE |
+--------+-------+
| A1     |    10 |
| B1     |  1000 |
| B2     |   100 |
+--------+-------+

输出:

df_new
+-----+---------+--------+--------+------+-----------+
| No  |  col1   |  col2  |  col3  | col4 | ref_value |
+-----+---------+--------+--------+------+-----------+
| 523 |     340 |   5930 |   1000 |   10 | A1        |
| 523 |    1000 |   1000 |   1000 |   43 | A1        |
| 523 |  186700 |   1500 |  63200 |   64 | B2        |
| 732 |  100000 | 943000 | 375000 |  325 | B1        |
| 732 | 1000000 | 656000 | 235000 |   63 | B1        |
+-----+---------+--------+--------+------+-----------+

【问题讨论】:

  • 首先,函数是做什么的?
  • 我添加了更多代码。认为没有它可能会更容易。我只是执行一个简单的数学运算。
  • @MaMo - 可以添加一些示例数据吗?似乎这里应该有一些join
  • 我添加了一个非常简单的示例。我想再提一次,我的编码已经有效,但由于 for 循环导致效率不高

标签: python pandas function for-loop


【解决方案1】:

我认为最好使用这个矢量化解决方案 - 由mul 与由map 创建的Series 相乘:

c = ['col1','col2','col3']
df[c] = df[c].mul(df['ref_value'].map(ref.set_index('SOURCE')['VALUE']), axis=0)
print (df)
    No     col1    col2    col3  col4 ref_value
0  523      340    5930    1000    10        A1
1  523     1000    1000    1000    43        A1
2  523   186700    1500   63200    64        B2
3  732   100000  943000  375000   325        B1
4  732  1000000  656000  235000    63        B1

详情

print (df['ref_value'].map(ref.set_index('SOURCE')['VALUE']))
0      10
1      10
2     100
3    1000
4    1000
Name: ref_value, dtype: int64

如果需要创建函数:

def func(df, cols, col_ref):
    df[cols] = df[cols].mul(df[col_ref].map(ref.set_index('SOURCE')['VALUE']), axis=0)
    return df

df_new = func(df, ['col1','col2','col3'], 'ref_value')
print (df_new)

    No     col1    col2    col3  col4 ref_value
0  523      340    5930    1000    10        A1
1  523     1000    1000    1000    43        A1
2  523   186700    1500   63200    64        B2
3  732   100000  943000  375000   325        B1
4  732  1000000  656000  235000    63        B1

【讨论】:

  • 完美,节省了我很多时间!谢谢 :) 如果我需要省略特定的 ref_value,例如我想为ref_value == 'B2' 保留 col1,col2,col3,我可以以一种不错的方式将其添加到函数中吗?现在,我在调用函数之前对数据框进行了子集化,但随后我必须将返回的数据框与我再次遗漏的行合并。
  • @MaMo - 我认为boolean indexing 很好,在df[cols] = df[cols].mul(df[col_ref].map(ref.set_index('SOURCE')['VALUE']), axis=0) 之前调用df = df[df.ref_value == 'B2']
  • 所以我在乘法之前拆分,然后将结果和原始df合并,然后合并?
  • 我认为还需要其他东西,如果只想按条件应用功能mask = df.ref_value == 'B2' 然后df.loc[mask, cols] = df.loc[mask, cols].mul(df[col_ref].map(ref.set_index('SOURCE')['VALUE']), axis=0)
  • 我必须使用 not equal like this mask = df.ref_value != 'B2' 来排除这些行。但除此之外,您的解决方案可以完美运行并且速度非常快。非常感谢!
猜你喜欢
  • 2022-01-08
  • 2021-05-13
  • 2022-07-18
  • 2013-10-03
  • 2015-09-19
  • 1970-01-01
  • 2019-03-07
  • 2017-09-25
  • 1970-01-01
相关资源
最近更新 更多