You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

跨行比较DataFrame同列值报错:Columns must be same length as key

DataFrame跨行对比同品类年度价格变化问题

问题说明

需要为DataFrame添加change列,规则是:每个水果当年价格较上年下降时填"Reduced",上升时填"Increased";原代码运行时报错Columns must be same length as key,且存在索引匹配隐患。

原代码如下:

df = pd.DataFrame({
    'Fruit': ['Apple', 'Orange', 'Grapes', 'Bananas', 'Apple', 'Orange',
              'Grapes', 'Bananas'],
    'year': [2015, 2015, 2015, 2015, 2016, 2016, 2016, 2016],
    'price': [5, 7, 7, 9, 12, 9, 9, 4],
    'stock': [11, 8, 10, 6, 6, 5, 9, 12]})
df['change'] = ''

df['change'] = df.apply(
    lambda x:
        'Reduced' if x['price'] < df.loc[
            (df['Fruit'] == x['Fruit']) & (df['year'] == (x['year']-1))
        ]['price'].any() else x['change'],
    axis=1)

错误原因

  1. 逻辑错误:df.loc[...]['price'].any()仅判断是否存在上一年的价格数据,返回布尔值,而非具体的价格数值,无法和当前行价格做大小对比。
  2. 效率与匹配问题:apply逐行处理效率极低,且如果数据排序混乱,会出现索引不匹配的问题;同时逐行返回的结果可能因逻辑错误导致长度不匹配,触发Columns must be same length as key报错。

正确解决方案

使用groupby+shift实现分组跨行取数,这是Pandas处理同类分组跨行对比的标准高效方法:

方法1:结合shift与numpy.where

import pandas as pd
import numpy as np

df = pd.DataFrame({
    'Fruit': ['Apple', 'Orange', 'Grapes', 'Bananas', 'Apple', 'Orange',
              'Grapes', 'Bananas'],
    'year': [2015, 2015, 2015, 2015, 2016, 2016, 2016, 2016],
    'price': [5, 7, 7, 9, 12, 9, 9, 4],
    'stock': [11, 8, 10, 6, 6, 5, 9, 12]
})

# 按水果分组,获取上一年的价格(shift(1)将组内上一行数据下移)
df['prev_price'] = df.groupby('Fruit')['price'].shift(1)

# 对比当前价格与上一年价格,生成change列
df['change'] = np.where(
    df['price'] < df['prev_price'], 
    'Reduced',
    np.where(
        df['price'] > df['prev_price'], 
        'Increased',
        'No Change'
    )
)

# 为第一年(无上年数据)的行单独赋值
df.loc[df['year'] == 2015, 'change'] = 'No Previous Data'

# 可选:删除辅助列prev_price
# df = df.drop('prev_price', axis=1)

print(df)

方法2:使用pd.cut生成标签

import pandas as pd

df = pd.DataFrame({
    'Fruit': ['Apple', 'Orange', 'Grapes', 'Bananas', 'Apple', 'Orange',
              'Grapes', 'Bananas'],
    'year': [2015, 2015, 2015, 2015, 2016, 2016, 2016, 2016],
    'price': [5, 7, 7, 9, 12, 9, 9, 4],
    'stock': [11, 8, 10, 6, 6, 5, 9, 12]
})

df['prev_price'] = df.groupby('Fruit')['price'].shift(1)

# 用cut根据价格区间生成标签
df['change'] = pd.cut(
    df['price'],
    bins=[-float('inf'), df['prev_price'], float('inf')],
    labels=['Reduced', 'Increased']
)

# 填充无上年数据的行
df['change'] = df['change'].fillna('No Previous Data')

print(df)

注意事项

如果数据中存在年份不连续、水果年份缺失的情况,需先对数据按Fruit和year排序,确保shift能正确获取上一年数据:

df = df.sort_values(['Fruit', 'year'])

内容的提问来源于stack exchange,提问作者Nitin

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.10 19:45:32