如何使用来自另一个 DataFrame 的输入以最佳方式将函数应用于 DataFrame 的所有项?

How to optimally apply a function on all items of a dataframe using inputs from another dataframe?

提问人:sweetdream 提问时间:5/29/2012 最后编辑:Communitysweetdream 更新时间:7/30/2019 访问量:2633

问:

我是 python 的新手,我正在努力用熊猫做简单的事情。我想将相同的函数应用于给定数据集的每个项目,但使用与时间相关的参数。

我正在使用以时间戳为索引的熊猫。DataFrame

比方说:

a(i,j) 是数据帧 A 中 j 列中的第 i 个元素(时间戳/索引 = i 和列 = j)

b(i) 是数据帧 B 中的第 i 个元素(具有单列)

我想计算:

c(i, j) = fct(a(i, j), b(i))

其中 fct 是一个有两个参数的函数 z = fct(x, y)

我写了一个代码,可以正确地做到这一点,但它可能不是最佳的(非常慢)。 对于示例,我只是使用了一个简单的函数 fct(但在 reallity 中它更复杂)

输入:

  • df_data:带有 index=timestamp 和几列pandas.DataFrame
  • df_parameter:有 1 列包含瞬态参数pandas.DataFrame

代码如下:

# p.concat is required as timestamps are not identical in df_data & df_parameters
import numpy as np
import pandas as p

temp = p.concat([df_data, df_parameter], join='inner', axis=1)
index = temp.index
np_data = temp[nacelleWindSpeeds.columns].values
np_parameter = temp[airDensity.columns].values

import math 

def fct(x, y):
    return math.pow(x, y)

def test(np_data, np_parameter):
    np_result = np.empty(np_data.shape, dtype=float)
    it = np.nditer(np_data, flags=['multi_index'])

    while not it.finished:
        np_result[it.multi_index] = fct(it[0].item(),
                                        np_parameter[it.multi_index[0]][0])
        it.iternext()

    df_final=p.DataFrame(data=np_result, index=index)
    return df_final

final=test(np_data, np_parameter)   

final.to_csv(r'C:\temp\test.csv', sep=';')

以下是一些示例数据:

df_data

01/03/2010 00:00  ;  9  ;  5  ;  7  
01/03/2010 00:10  ;  9  ;  1  ;  4  
01/03/2010 00:20  ;  5  ;  3  ;  8  
01/03/2010 00:30  ;  7  ;  7  ;  1  
01/03/2010 00:40  ;  8  ;  2  ;  3  
01/03/2010 00:50  ;  0  ;  3  ;  4     
01/03/2010 01:00  ;  4  ;  3  ;  2  
01/03/2010 01:10  ;  6  ;  2  ;  2  
01/03/2010 01:20  ;  6  ;  8  ;  5  
01/03/2010 01:30  ;  7  ;  7  ;  0  

df_parameter

01/03/2010 00:00  ;  2  
01/03/2010 00:10  ;  5  
01/03/2010 00:20  ;  2  
01/03/2010 00:30  ;  3  
01/03/2010 00:40  ;  0  
01/03/2010 00:50  ;  2  
01/03/2010 01:00  ;  4  
01/03/2010 01:10  ;  3  
01/03/2010 01:20  ;  3  
01/03/2010 01:30  ;  1  

最后

01/03/2010 00:00  ;  81  ;  25  ;  49  
01/03/2010 00:10  ;  59049  ;  1  ;  1024  
01/03/2010 00:20  ;  25  ;  9  ;  64  
01/03/2010 00:30  ;  343  ;  343  ;  1  
01/03/2010 00:40  ;  1  ;  1  ;  1  
01/03/2010 00:50  ;  0  ;  9  ;  16  
01/03/2010 01:00  ;  256  ;  81  ;  16  
01/03/2010 01:10  ;  216  ;  8  ;  8  
01/03/2010 01:20  ;  216  ;  512  ;  125  
01/03/2010 01:30  ;  7  ;  7  ;  0  

非常感谢您的帮助,

帕特里克

python numpy 熊猫

评论

0赞 bmu 5/29/2012
请提供一些示例数据,因为从您的代码中很难理解您要做什么。
0赞 sweetdream 5/30/2012
感谢您的关注 bmu.我刚刚添加了这个例子。

答:

1赞 bmu 5/30/2012 #1

不知道这是否是最佳方法,但这更简单,应该更有效,因为它使用矢量化函数进行计算:

def func(x, y):
    return x ** y

data = pd.read_csv('data.dat', sep=';', index_col=0, parse_dates=True,
                    header=None, names='abc')
para = pd.read_csv('parameter.dat', sep=';', index_col=0, parse_dates=True,
                    header=None, names=['para'])

for col in data:
    data['%s_result' % col] = func(data[col], para.para)

print data

结果

                     a  b  c  a_result  b_result  c_result
2010-01-03 00:00:00  9  5  7        81        25        49
2010-01-03 00:10:00  9  1  4     59049         1      1024
2010-01-03 00:20:00  5  3  8        25         9        64
2010-01-03 00:30:00  7  7  1       343       343         1
2010-01-03 00:40:00  8  2  3         1         1         1
2010-01-03 00:50:00  0  3  4         0         9        16
2010-01-03 01:00:00  4  3  2       256        81        16
2010-01-03 01:10:00  6  2  2       216         8         8
2010-01-03 01:20:00  6  8  5       216       512       125
2010-01-03 01:30:00  7  7  0         7         7         0

如果你的实际函数更复杂,你甚至应该尝试对它进行矢量化,或者使用 numpy.vectorize() 作为下一个最佳解决方案。

评论

0赞 sweetdream 5/30/2012
您好,感谢您的回复和这个漂亮的表述。不幸的是,只有当您能够使用矢量化函数时,这才正常工作。就我而言,我的函数使用字典,我认为这不能矢量化。我错了?
0赞 bmu 5/30/2012
@user1415325 在大多数情况下,您可以对函数进行矢量化,并且应该这样做以提高效率。你有没有看过下一个最佳解决方案?numpy.vectorize()
0赞 sweetdream 6/4/2012
多谢。这确实是我所缺少的。“神奇的”numpy.vectorize() 函数!!!再次感谢。
0赞 bmu 6/4/2012
@user1415325我更新了答案。如果这回答了您的问题,请考虑将答案标记为已解决。
0赞 sweetdream 6/5/2012
奇怪的是,首先从 DataFrame 中提取数据(作为 numpy 数组),然后运行函数,最后重建一个 DataFrame,速度更快......
0赞 nathanielng 9/5/2015 #2

一种方法是使用函数,或者 ;也可以使用 lambda 函数来做到这一点。例如:mapnumpy.vectorize

import numpy as np
def fct(x, y):
    return x**y

A = np.array([[9, 5, 7],
       [9, 1, 4],
       [5, 3, 8],
       [7, 7, 1],
       [8, 2, 3],
       [0, 3, 4],
       [4, 3, 2],
       [6, 2, 2],
       [6, 8, 5],
       [7, 7, 0]])
B = np.array([2, 5, 2, 3, 0, 2, 4, 3, 3, 1])
C1 = np.asarray(map(fct, A, B))
C2 = np.asarray(map(lambda x,y: x**y, A, B))

vfunc = np.vectorize(fct)
C3 = vfunc(A, np.row_stack(B))

或通过 Pandas:

import pandas as pd
pdA = pd.DataFrame(A)
pdB = pd.DataFrame(B)
C4 = np.asarray(map(lambda x,y: x**y, pdA.values, pdB.values))
pdC = pd.DataFrame(C4)

请注意,C1、C2、C3 和 C4 都相等:

>>> print np.array_equal(C1,C2), np.array_equal(C2,C3), np.array_equal(C3,C4)
True True True