使用Groupby并对该组中列的每N行应用自定义函数

2024-06-14 04:11:15 发布

您现在位置:Python中文网/ 问答频道 /正文

我有一个pandas数据帧,我想对一列执行groupby,并对另一列应用自定义函数。但该函数必须应用于apply列的每两个条目。你知道吗

df = pd.DataFrame({'id':[1,1,2,2,2,3,3,3,3,3], 'vals':['ANZ', 'ABC', 'SAT', 'SATYA', 'SQL', 'WER', 'DEA', 'KIP', 'FTY', 'TCZ'] })
#df
id  vals  
1   ANZ
1   ABC
2   SAT
2   SATYA
2   SQL
3   WER
3   DEA
3   KIP
3   FTY
3   TCZ
# i need a column "res", as a func applied to column vals's each two rows on a group by on column 'id'. ### myfunc takes two argument and return one value.
df['res'] = df.groupby('id')['vals'].apply(myfunc)
###df
id  vals   res
1   ANZ    myfunc(None, ANZ)
1   ABC    myfunc('ANZ', 'ABC')
2   SAT    myfunc(None, 'SAT')
2   SATYA  myfunc('SAT', 'SATYA')
2   SQL    myfunc('SATYA', 'SQL')
3   WER    myfunc(None, 'WER')
3   DEA    myfunc('WER', 'DEA')
3   KIP    myfunc('DEA', 'KIP')
3   FTY    myfunc('KIP', 'FTY')
3   TCZ    myfunc('FTY', 'TCZ')

但目前无法形成apply()的表达式,因为对于group by.apply(x),x将是一个系列,我无法找到在x(pandas groupby series object)上使用索引访问的方法。你知道吗

请指导我如何做到这一点,谢谢在Adv。你知道吗


Tags: iddfsqlmyfuncsatapplyabcwer
3条回答

所以我尝试了下面的方法。你知道吗

Myfunc用于查找两个字符串之间的字符串相似性,为此我使用了非常棒的fuzzyfuzzy库

from fuzzywuzzy import fuzz

def myfunc(x):
    x = x.tolist() # converted series to list
    y = []
    for i in range(0, len(x)):
        if i == 0:
            y.append(None)
        else:
            ## apply ratio between prev_Row_vals and Current_Row_vals
            y.append(fuzz.token_set_ratio(x[i - 1], x[i]) / 10)
    return y

  ## Now the group by and apply/transform function
  df['res'] = df.groupby('id')['vals'].transform(lambda x: myfunc(x))

但我不确定这是否是Python的方式做这样的事。请告诉我,如果有更多的Python的方式来做这件事。谢谢。你知道吗

我提议用另一种方式来完成你的任务。你知道吗

从使用前一行的vals生成列开始 在当前组中。我把它命名为prev。你知道吗

然后使用applydf中的每一行调用函数,替换 结果dores列。 myfunc获取当前行,必须提取prevvals,然后返回结果。你知道吗

剩下的事情就是删除prev列。你知道吗

所以整个脚本可以如下所示:

import pandas as pd

def myfunc(x):
    pr = x.prev
    t1 = pr if pd.notnull(pr) else None
    t2 = x.vals
    return f'myfunc({repr(t1)}, {repr(t2)})'

df = pd.DataFrame({'id':[1,1,2,2,2,3,3,3,3,3], 'vals':
    ['ANZ', 'ABC', 'SAT', 'SATYA', 'SQL', 'WER', 'DEA', 'KIP', 'FTY', 'TCZ'] })
df['prev'] = df.groupby('id').shift()
df['res'] = df.apply(myfunc, axis=1)
df.drop('prev', axis=1, inplace=True)

当您print(df)时,您将得到:

   id   vals                     res
0   1    ANZ     myfunc(None, 'ANZ')
1   1    ABC    myfunc('ANZ', 'ABC')
2   2    SAT     myfunc(None, 'SAT')
3   2  SATYA  myfunc('SAT', 'SATYA')
4   2    SQL  myfunc('SATYA', 'SQL')
5   3    WER     myfunc(None, 'WER')
6   3    DEA    myfunc('WER', 'DEA')
7   3    KIP    myfunc('DEA', 'KIP')
8   3    FTY    myfunc('KIP', 'FTY')
9   3    TCZ    myfunc('FTY', 'TCZ')

IIUC,你可以试试下面的

df['new_value']=df.vals.shift()
df.groupby(df.index//2)['vals','new_value'].apply(lambda x: pd.Series(list(zip(x.new_value,x.vals))))\
.stack().reset_index(drop=True)

0      (nan, ANZ)
1      (ANZ, ABC)
2      (ABC, SAT)
3    (SAT, SATYA)
4    (SATYA, SQL)
5      (SQL, WER)
6      (WER, DEA)
7      (DEA, KIP)
8      (KIP, FTY)
9      (FTY, TCZ)

编辑稍微修改代码以匹配输出:

a=df.groupby('id')['vals'].apply(lambda x: pd.DataFrame(list(zip(x.shift(),x))))
df['new']=list(zip(a[0],a[1]))
print(df)

   id   vals           new
0   1    ANZ    (nan, ANZ)
1   1    ABC    (ANZ, ABC)
2   2    SAT    (nan, SAT)
3   2  SATYA  (SAT, SATYA)
4   2    SQL  (SATYA, SQL)
5   3    WER    (nan, WER)
6   3    DEA    (WER, DEA)
7   3    KIP    (DEA, KIP)
8   3    FTY    (KIP, FTY)
9   3    TCZ    (FTY, TCZ)

相关问题 更多 >