【问题标题】:How to select values based on array's index from relative index within pandas groups如何根据数组的索引从熊猫组中的相对索引中选择值
【发布时间】:2021-03-18 17:16:45
【问题描述】:

我有一个 DataFrame,它已经按 ('year', 'month') 列排序,如下所示:

df = pd.DataFrame({
    'year': [2020, 2020, 2020, 2021, 2021, 2021, 2021],
    'month': [1, 2, 5, 2, 4, 7, 9],
    'values': [
        ['a', 'b', 'c'], ['a', 'b', 'c'], ['a', 'b', 'c'],
        ['A', 'B', 'C', 'D'], ['A', 'B', 'C', 'D'], ['A', 'B', 'C', 'D'], ['A', 'B', 'C', 'D']
    ]
})

print(df)

    year    month   values
0   2020    1       ['a', 'b', 'c']
1   2020    2       ['a', 'b', 'c']
2   2020    5       ['a', 'b', 'c']
3   2021    2       ['A', 'B', 'C', 'D']
4   2021    4       ['A', 'B', 'C', 'D']
5   2021    7       ['A', 'B', 'C', 'D']
6   2021    9       ['A', 'B', 'C', 'D']

我想创建一个名为'value' 的新列,其中包含'values' 数组中i-th 元素的值,其中i 是对应月份的索引,按年份分组。在这种情况下,结果将是:

    year    month   values                  value
0   2020    1       ['a', 'b', 'c']         'a'
1   2020    2       ['a', 'b', 'c']         'b'
2   2020    5       ['a', 'b', 'c']         'c'
3   2021    2       ['A', 'B', 'C', 'D']    'A'
4   2021    4       ['A', 'B', 'C', 'D']    'B'
5   2021    7       ['A', 'B', 'C', 'D']    'C'
6   2021    9       ['A', 'B', 'C', 'D']    'D'

我假设数组上没有数据丢失。我尝试过的一些行涉及使用.groupby('year'),后跟.get_loc('month'),但到目前为止无法获得正确的结果。

编辑:

有一个细节我忘了提:月份不一定在一个统一的范围内,因此索引并不总是month-1。我已经编辑了有问题的 DataFrame 以反映这种细微差别。

【问题讨论】:

  • 根据您的编辑查看我对答案的编辑,即索引并不总是month-1
  • 也根据数据样本变化进行了编辑。

标签: python pandas


【解决方案1】:

理解

df.assign(value=[v[m-1] for v, m in zip(df['values'], df['month'])])

   year  month        values value
0  2020      1     [a, b, c]     a
1  2020      2     [a, b, c]     b
2  2020      3     [a, b, c]     c
3  2021      1  [A, B, C, D]     A
4  2021      2  [A, B, C, D]     B
5  2021      3  [A, B, C, D]     C
6  2021      4  [A, B, C, D]     D

替代maplist.__getitem__

df.assign(value=[*map(list.__getitem__, df['values'], df['month'] - 1)])

【讨论】:

    【解决方案2】:

    让我们试试lookup

    df['out'] = pd.DataFrame(df['values'].tolist(),index=df.index).lookup(df.index,df.month-1)
    df
    Out[372]: 
       year  month        values out
    0  2020      1     [a, b, c]   a
    1  2020      2     [a, b, c]   b
    2  2020      3     [a, b, c]   c
    3  2021      1  [A, B, C, D]   A
    4  2021      2  [A, B, C, D]   B
    5  2021      3  [A, B, C, D]   C
    6  2021      4  [A, B, C, D]   D
    

    因为lookup 将被删除,所以对于未来的人来说

    df['out'] = pd.DataFrame(df['values'].tolist(),index=df.index).values[df.index,df.month-1]
    

    【讨论】:

      【解决方案3】:

      axis=1 上使用df.apply()

      df['value'] = df.apply(lambda x: x['values'][x['month']-1], axis=1)
      

      或者,对于大数据,使用list([map()]) 表示better system performance(执行时间):

      df['value'] = list(map((lambda x, y: x[y]), df['values'], df['month'] - 1))
      

      输出:

         year  month        values value
      0  2020      1     [a, b, c]     a
      1  2020      2     [a, b, c]     b
      2  2020      3     [a, b, c]     c
      3  2021      1  [A, B, C, D]     A
      4  2021      2  [A, B, C, D]     B
      5  2021      3  [A, B, C, D]     C
      6  2021      4  [A, B, C, D]     D
      

      编辑:(根据OP的编辑,“索引并不总是month-1”)

      在发布答案后响应 OP 的编辑,即:

      月份不一定在一个统一的范围内,因此索引 并不总是第 1 个月。

      虽然问题的原始版本中提到的以下要求仍然适用:

      我想创建一个名为“值”的新列,其中包含值 'values' 数组中的第 i 个元素,其中 i 是 对应的月份,按年份分组。

      解决方案将修改如下:

      第 1 步:在按年份分组的组中创建相应月份的索引

      通过df.groupbySeries.transform设置列value_idx如下:

      使用Series.transform 中的x.index - x.index[0] 获取pandas 组内的相对索引。

      df['value_idx'] = df.groupby('year')['values'].transform(lambda x: x.index - x.index[0])
      
      print(df)
      
         year  month        values  value_idx
      0  2020      1     [a, b, c]          0
      1  2020      2     [a, b, c]          1
      2  2020      5     [a, b, c]          2
      3  2021      2  [A, B, C, D]          0
      4  2021      4  [A, B, C, D]          1
      5  2021      7  [A, B, C, D]          2
      6  2021      9  [A, B, C, D]          3
      

      value_idx 列中的值独立于month 的值设置,并且是各个年份组内的相对索引。

      第 2 步:根据列 value_idx 中的索引设置列 value,独立于列 month

      使用df.apply()list(map()) 设置列value

      要么:

      df['value'] = df.apply(lambda x: x['values'][x['value_idx']], axis=1)
      

      或:

      df['value'] = list(map((lambda x, y: x[y]), df['values'], df['value_idx']))
      

      打印(df)输出:

         year  month        values  value_idx value
      0  2020      1     [a, b, c]          0     a
      1  2020      2     [a, b, c]          1     b
      2  2020      5     [a, b, c]          2     c
      3  2021      2  [A, B, C, D]          0     A
      4  2021      4  [A, B, C, D]          1     B
      5  2021      7  [A, B, C, D]          2     C
      6  2021      9  [A, B, C, D]          3     D
      

      如果需要,您可以选择清理value_idx 列:

      df = df.drop(columns='value_idx')
      

      打印(df)输出:

         year  month        values value
      0  2020      1     [a, b, c]     a
      1  2020      2     [a, b, c]     b
      2  2020      5     [a, b, c]     c
      3  2021      2  [A, B, C, D]     A
      4  2021      4  [A, B, C, D]     B
      5  2021      7  [A, B, C, D]     C
      6  2021      9  [A, B, C, D]     D
      

      【讨论】:

        猜你喜欢
        • 2018-02-08
        • 2021-11-02
        • 2017-07-03
        • 2018-05-28
        • 2020-07-17
        • 2020-01-12
        • 1970-01-01
        • 2018-09-27
        • 1970-01-01
        相关资源
        最近更新 更多