带有groupby、apply和transform的高级逻辑 - 将行值与之前的值进行比较并创建新列

问题描述 投票:0回答:1

我有以下熊猫数据框:

d= {'Time': [0,1,2,0,1,2,2,3,4], 'Price': ['Auction', 'Auction','800','900','By Negotiation','700','250','250','Make Offer'],'Item': ['Picasso', 'Picasso', 'Picasso', 'DaVinci', 'DaVinci', 'DaVinci', 'Dali', 'Dali', 'Dali']}
df = pd.DataFrame(data=d)

我想创建第四列“列表历史记录”,其中指定以下内容:

  • “第一次看到”如果列表是第一次看到(这不一定是时间== 0)
  • “持续上市”如果价格字段从一个时间点到下一个时间点没有变化
  • 'Price->Auction' 如果价格字段从数值(实际上在我的数据帧中编码为字符串)更改为 'Auction' 字符串,反之亦然,如果价格从数值更改为 'Auction' ' 字符串。
  • 我希望代码与确切的价格字段字符串无关,例如:如果价格字段从数值更改为“通过协商”,则为“价格->通过协商”

我想按Item分组,然后应用上面的逻辑。

使用类似以下内容来查找列表是否是“首次看到”非常简单:

df['Price_coerced_to_numeric'] = pd.to_numeric(df['Price'], errors='coerce')
df['Price_diff'] = df.groupby(['Item'])['Price_coerced_to_numeric'].diff(1)

我怀疑有一种使用pandas apply和transform的方法,但我还没能解决。非常感谢任何提示。

python pandas group-by pandas-apply
1个回答
1
投票

您可以使用

groupby.shift
numpy.select
:

# replace numbers by "Price"
price = df['Price'].mask(pd.to_numeric(df['Price'], errors='coerce')
                           .notna(), 'Price')
# get previous price
prev_price = price.groupby(df['Item']).shift()

# identify first row per Item
m1 = ~df['Item'].duplicated()
# identify change in price
m2 = price.ne(prev_price)

# combine conditions
df['Listing-history'] = np.select([m1, m2],
                                  ['first seen', prev_price+'->'+price],
                                  'ongoing listing')

输出:

   Time           Price     Item        Listing-history
0     0         Auction  Picasso             first seen
1     1         Auction  Picasso        ongoing listing
2     2             800  Picasso         Auction->Price
3     0             900  DaVinci             first seen
4     1  By Negotiation  DaVinci  Price->By Negotiation
5     2             700  DaVinci  By Negotiation->Price
6     2             250     Dali             first seen
7     3             250     Dali        ongoing listing
8     4      Make Offer     Dali      Price->Make Offer

如果你真的想使用

groupby.transform
,你可以稍微重构一下代码:

def history(col):
    price = col.mask(pd.to_numeric(col, errors='coerce').notna(), 'Price')
    prev_price = price.shift()
    return ((prev_price+'->'+price)
            .where(price.ne(prev_price), 'ongoing listing')
            .fillna('first seen') 
           )

df['Listing-history'] = df.groupby('Item')['Price'].transform(history)

如果原始列中可以有 NaN,则为变体:

def history(col):
    price = col.mask(pd.to_numeric(col, errors='coerce').notna(), 'Price')
    prev_price = price.shift()
    out = (prev_price+'->'+price).where(price.ne(prev_price), 'ongoing listing')
    out.iat[0] = 'first seen'
    return out

df['Listing-history'] = df.groupby('Item')['Price'].transform(history)
© www.soinside.com 2019 - 2024. All rights reserved.