如何在具有重复值的行上有效地使用pd.DataFrame.apply?

时间:2017-10-17 20:19:20

标签: python pandas dataframe split apply

我正在应用的功能有点贵,因此我希望它只为唯一值计算一次值。

我能够提出的唯一解决方案如下:

此步骤因为apply不适用于数组,所以我必须将唯一值转换为系列。

new_vals = pd.Series(data['column'].unique()).apply(function)

这个因为.merge必须用在数据帧上。

new_dataframe = pd.DataFrame( index = data['column'].unique(), data = new_vals.values)

最后合并结果

yet_another= pd.merge(data, new_dataframe, right_index = True, left_on = column)
data['calculated_column'] = yet_another[0]

所以基本上我必须将我的值转换为Series,应用函数,转换为Dataframe,合并结果并使用该列创建新列。

我想知道是否有一些不那么混乱的单行解决方案。 pythonic不会涉及多次重新构建对象类型的东西。我尝试过分组,但我无法弄清楚如何做到这一点。

我最好的猜测就是沿着这些方向做点什么

data[calculated_column] = dataframe.groupby(column).index.apply(function)

但这也不对。

这是一项我经常做的操作,想要学习更好的方法,但经常不足以让我上次使用它时很容易找到,所以我最终重新计算了一堆东西然后再次。

如果没有好的解决方案,我想我可以将这个功能添加到我的常用工具库中,这是我享乐主义的>来自me_tools import *

def apply_unique(data, column, function):
    new_vals = pd.Series(data[column].unique()).apply(function)
    new_dataframe = pd.DataFrame( data = new_vals.values, index =         
    data[column].unique() )
    result = pd.merge(data, new_dataframe, right_index = True, left_on = column)
    return result[0]

1 个答案:

答案 0 :(得分:0)

我会做这样的事情:

def apply_unique(df, orig_col, new_col, func):
    return df.merge(df[[orig_col]]
                    .drop_duplicates()
                    .assign(**{new_col: lambda x: x[orig_col].apply(func)}
                           ), how='inner', on=orig_col)

这将返回与执行相同的DataFrame:

df[new_col] = df[orig_col].apply(func)

但是当有许多重复时,性能会更高。

工作原理:

我们将原始DataFrame(调用)连接到另一个包含两列的DataFrame(已传递);原始列和新列从原始列转换。

传递的DataFrame中的新列使用.assign和lambda函数进行分配,从而可以将函数应用于已对其执行.drop_duplicates()的DataFrame。

此处仅使用dict以方便使用,因为它允许将列名称作为str传入。

修改 顺便说一句:如果new_col已经存在,最好放弃merge,否则new_col会为每个if new_col in df: df = df.drop(new_col, axis='columns') 附加后缀

// object notation
var myCar = new Object();
myCar.color = 'red';
// JSON notation
var myOtherCar = { color: 'red' };
console.log( 'myOtherCar.color: ' + myOtherCar.color );
// see how we initialized the value as a string and then changed it to an array of ints?
myOtherCar.color = [1,2,3,4];
console.log( 'myOtherCar.color: ' + myOtherCar.color );
// see how we created a new property that wasn't declared in a class structure?
myOtherCar.gasTank = .5;
console.log( 'myOtherCar.gasTank: ' + myOtherCar.gasTank );
// Is the gas tank half full or half empty?