【问题标题】:Group latest values in pandas columns for a given id对给定 id 的 pandas 列中的最新值进行分组
【发布时间】:2021-07-15 14:41:51
【问题描述】:

我有一个 pandas 数据框,其中包含给定日期和用户的一些指标。

>>> pd.DataFrame({"user": ['juan','juan','juan','gonzalo'], "date": [1, 2, 3, 1], "var1": [1, 2, None, 1], "var2": [None, 4, 5, 6]})
      user  date  var1  var2
0     juan     1   1.0   NaN
1     juan     2   2.0   4.0
2     juan     3   NaN   5.0
3  gonzalo     1   1.0   6.0

现在,对于每个用户,我想为每个变量(var1、var2)提取 2 个更新的值,忽略 NaN,除非没有足够的值来填充数据。

作为参考,这应该是上述数据的结果数据框

user     var1_0  var1_1  var2_0  var2_1
juan       2.0     1.0     5.0    4.0
gonzalo    1.0      NaN    6.0    NaN

每个“历史”值都被添加为带有_0_1 后缀的新列。

【问题讨论】:

  • date 要排序以获取最近的列还是行顺序?

标签: python pandas dataframe


【解决方案1】:

如有必要,首先按DataFrame.sort_values 中的两列排序,并通过DataFrame.sort_values 整形并删除缺失值,按GroupBy.head 过滤每组的前2 行,然后通过GroupBy.cumcount 创建计数器列,并在DataFrame.pivot 中进行旋转扁平化MultiIndex:

df1 = (df.sort_values(['user','date'])
         .melt(id_vars='user', value_vars=['var1','var2'])
         .dropna(subset=['value'])
        )


df1 = df1.groupby(['user','variable']).head(2)
df1['g'] = df1.groupby(['user','variable']).cumcount(ascending=False)

df1 = df1.pivot(index='user', columns=['variable', 'g'], values='value')
#oldier pandas versions
#df1 = df1.set_index(['user','variable', 'g'])['value'].unstack([1,2])
df1.columns = df1.columns.map(lambda x: f'{x[0]}_{x[1]}')
df1 = df1.reset_index()
print (df1)
      user  var1_0  var1_1  var2_0  var2_1
0  gonzalo     1.0     NaN     6.0     NaN
1     juan     2.0     1.0     5.0     4.0

【讨论】:

  • 谢谢,按预期工作。更好的是,我也有没有旋转的数据框,所以我什至不需要.melt()
【解决方案2】:

您可以按 user 分组并聚合以获得 2 个最近的值。几乎所有的方式都在那里 - 但是你有一个元素列表而不是列。如果您想拥有实际的 2 列,则必须将新创建的列表拆分为列。完整代码:

import pandas as pd
import numpy as np

df = pd.DataFrame(
    {
        "user": ["juan", "juan", "juan", "gonzalo"],
        "date": [1, 2, 3, 1],
        "var1": [1, 2, None, 1],
        "var2": [None, 4, 5, 6],
    }
)

# This almost gets you there
df = (
    df.sort_values(by="date")
    .groupby("user")
    .agg({"var1": lambda x: x.dropna().head(2), "var2": lambda x: x.dropna().head(2)})
)

# Split the columns and get the correct column names
df[["var1_0", "var2_0"]] = df[["var1", "var2"]].apply(
    lambda row: pd.Series(el[0] if isinstance(el, np.ndarray) else el for el in row),
    axis=1,
)
df[["var1_1", "var2_1"]] = df[["var1", "var2"]].apply(
    lambda row: pd.Series(el[-1] if isinstance(el, np.ndarray) else None for el in row),
    axis=1,
)
print(df)

>>
               var1        var2  var1_0  var2_0  var1_1  var2_1
user                                                           
gonzalo         1.0         6.0     1.0     6.0     NaN     NaN
juan     [1.0, 2.0]  [4.0, 5.0]     1.0     4.0     2.0     5.0

【讨论】:

    猜你喜欢
    • 2019-12-20
    • 2018-07-04
    • 1970-01-01
    • 1970-01-01
    • 2021-02-09
    • 2021-08-17
    • 2018-06-01
    • 1970-01-01
    • 2021-10-30
    相关资源
    最近更新 更多