在 Pandas 中的相关行上应用函数
Apply function over relative rows in Pandas
似乎将函数应用于数据帧通常是 wrt 系列(例如 df.apply(my_fun))等函数索引 'one row at a time'。我的问题是,是否可以在以下意义上获得更大的灵活性:对于数据框 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)
Thoughts/Solutions和'map'或'transform'也很受欢迎。
从面向对象的方法来看,我可能会想象一行 df 被视为具有属性的对象 i) 指向其上方所有行的指针和 ii) 指向其下方所有行的指针。然后引用 row.above 和 row.below 以便在 df.loc[row, newcol]
处分配新值
总是可以查看封闭的执行框架:
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
您在评论中添加的特定示例的完整实现将是:
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_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']
此外,还有一些内置的标准处理函数,如 diff
、shift
、cumsum
、cumprod
,它们对相邻行进行操作,尽管范围是有限
似乎将函数应用于数据帧通常是 wrt 系列(例如 df.apply(my_fun))等函数索引 'one row at a time'。我的问题是,是否可以在以下意义上获得更大的灵活性:对于数据框 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)
Thoughts/Solutions和'map'或'transform'也很受欢迎。
从面向对象的方法来看,我可能会想象一行 df 被视为具有属性的对象 i) 指向其上方所有行的指针和 ii) 指向其下方所有行的指针。然后引用 row.above 和 row.below 以便在 df.loc[row, newcol]
处分配新值总是可以查看封闭的执行框架:
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
您在评论中添加的特定示例的完整实现将是:
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_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']
此外,还有一些内置的标准处理函数,如 diff
、shift
、cumsum
、cumprod
,它们对相邻行进行操作,尽管范围是有限