【问题标题】:Apply function over relative rows in Pandas在 Pandas 中的相关行上应用函数
【发布时间】:2015-07-21 04:56:50
【问题描述】:

似乎将函数应用于数据帧通常是 wrt 系列(例如 df.apply(my_fun)),因此此类函数索引“一次一行”。我的问题是是否可以在以下意义上获得更大的灵活性:对于数据框 df,编写一个函数 my_fun(row) 以便我们可以指向 行上方或下方该行。

例如,从以下开始:

def row_conditional(df, groupcol, appcol1, appcol2, newcol, sortcol, shift):
    """Input: df (dataframe): input data frame
              groupcol, appcol1, appcol2, sortcol (str): column names in df
              shift (int): integer to point to a row above or below current row
       Output: df with a newcol appended based on conditions
    """
    df[newcol] = ''  # fill new col with blank str
    list_results = []
    members = set(df[groupcol])
  for m in members:
     df_m = df[df[groupcol]==m].sort(sortcol, ascending=True)
     df_m = df_m.reset_index(drop=True)
     numrows_m = df_m.shape[0]
     for r in xrange(numrows_m):
     # CONDITIONS, based on rows above or below
         if (df_m.loc[r + shift, appcol1]>0) and (df_m.loc[r - shfit, appcol2]=='False'):
                df_m.loc[r, newcol] = 'old'
            else:
                 df_m.loc[r, newcol] = 'new' 
    list_results.append(df_m)
return pd.concat(list_results).reset_index(drop=True)

然后,我希望能够将上面的内容重写为:

def new_row_conditional(row, shift):
    """apply above conditions to row relative to row[shift, appcol1] and row[shift, appcol2]
    """
 return new value at df.loc[row, newcol]

最后执行:

df.apply(new_row_conditional)

也非常欢迎带有“地图”或“变换”的想法/解决方案。

从面向对象的方法来看,我可能会想象一行 df 被视为具有属性 i)指向其上方所有行的指针和 ii)指向其下方所有行的指针。然后引用 row.above 和 row.below 以便在 df.loc[row, newcol]

处分配新值

【问题讨论】:

  • 当然,另一种选择是编写一个使用 df.loc[i, col] 和 df.loc[i-1, col] 的 for 循环,但我通常发现 apply 或 transform 函数的计算速度更快
  • rolling_apply() 可以处理简单的情况。 iterrows 应该能够处理任何事情。它并不快,但我认为这里也不会有任何通用的解决方案。
  • 您是否考虑过使用shift 方法向上或向下移动行?如果您尝试使用特定相对位置的行,这很有效。

标签: python pandas apply


【解决方案1】:

人们总是可以查看封闭的执行框架:

import pandas
dataf = pandas.DataFrame({'a':(1,2,3), 'b':(4,5,6)})

import sys
def foo(roworcol):
    # current index along the axis
    axis_i = sys._getframe(1).f_locals['i']
    # data frame the function is applied to
    dataf = sys._getframe(1).f_locals['self']
    axis = sys._getframe(1).f_locals['axis']
    # number of elements along the chosen axis
    n = dataf.shape[(1,0)[axis]]
    #  print where we are
    print('index: %i - %i items before, %i items after' % (axis_i,
                                                           axis_i,
                                                           n-axis_i-1))

函数函数foo内有:

  • roworcol当前元素退出迭代
  • axis 选择的轴
  • axis_i 沿所选轴的索引
  • dataf数据框

这都需要在数据框中指向前后。

>>> dataf.apply(foo, axis=1)
index: 0 - 0 items before, 2 items after
index: 1 - 1 items before, 1 items after
index: 2 - 2 items before, 0 items after

您在 cmets 中添加的特定示例的完整实现将是:

import pandas
import sys
df = pandas.DataFrame({'a':(1,2,3,4), 'b':(5,6,7,8)})

def bar(row, k):
    axis_i = sys._getframe(2).f_locals['i']
    # data frame the function is applied to
    dataf = sys._getframe(2).f_locals['self']
    axis = sys._getframe(2).f_locals['axis']
    # number of elements along the chosen axis
    n = dataf.shape[(1,0)[axis]]
    if axis_i == 0 or axis_i == (n-1):
        res = 0
    else:
        res = dataf['a'][axis_i - k] + dataf['b'][axis_i + k]
    return res

您会注意到,每当映射函数的签名中存在其他参数时,我们都需要向上跳转 2 帧。

>>> df.apply(bar, args=(1,), axis=1)
0     0
1     8
2    10
3     0
dtype: int64

您还会注意到,您提供的具体示例可以通过其他可能更简单的方法来解决。上面的解决方案是非常通用的,因为它允许您在从被映射的行越狱时使用map,但它也可能违反关于map 正在做什么的假设,例如。通过假设对行进行独立计算,剥夺了您轻松并行化的机会。

【讨论】:

  • 谢谢。把你的答案打成蝴蝶结:假设 df = pd.DataFrame({'a':(1,2,3,4), 'b':(5,6,7,8)}) 并让 k > 0一个正数。我们如何定义一个 bar(row, k) 方法,以便如果两个加数相对于当前“索引”存在,则它返回 a[index + k] + b[index - k],否则返回 0?对于 k = 1,我们应该得到,对于 df['new'] = df.apply(bar, args=(k,), axis=1),结果如下: list(df['new']) = [ 0, 8, 10, 0]
  • 谢谢!你已经对我的一般问题提供了一个很好解释的答案。您的 cmets 也会导致进一步的探索
【解决方案2】:

创建索引移动的重复数据帧,并并行循环它们的行。

df_pre = df.copy()
df_pre.index -= 1
result = [fun(x1, x2) for x1, x2 in zip(df_pre.iterrows(), df.iterrows()]

这假设您实际上想要该行中的所有内容。例如,您当然可以进行直接操作

result = df_pre['col'] - df['col']

此外,还有一些内置的标准处理函数,如diffshiftcumsumcumprod,它们确实对相邻行进行操作,但范围有限。

【讨论】:

    猜你喜欢
    • 2018-05-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-11-14
    • 2023-04-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多