【问题标题】:Pandas lookup from one of multiple columns, based on valuePandas 根据值从多个列之一中查找
【发布时间】:2014-11-14 03:18:26
【问题描述】:

我有以下数据框:

Date    best    a    b    c    d
1990    a       5    4    7    2
1991    c       10   1    2    0
1992    d       2    1    4    12
1993    a       5    8    11   6

我想做一个如下的数据框:

Date    best    value   
1990    a       5
1991    c       2
1992    d       12
1993    a       5

所以我希望通过使用列名来查找基于另一个行值的值。例如,第二个 df 中 1990 的值应从第一个 df 中查找“a”,第二行应从第一个 df 中查找“c”(=2)。

有什么想法吗?

【问题讨论】:

    标签: python pandas numpy dataframe


    【解决方案1】:

    使用looking up values by index column labels,因为DataFrame.lookup 自1.2.0 版起已被弃用:

    idx, cols = pd.factorize(df['best'])
    df['value'] = df.reindex(cols, axis=1).to_numpy()[np.arange(len(df)), idx]
    print (df)
       Date best   a  b   c   d  value
    0  1990    a   5  4   7   2      5
    1  1991    c  10  1   2   0      2
    2  1992    d   2  1   4  12     12
    3  1993    a   5  8  11   6      5
    

    【讨论】:

      【解决方案2】:

      使用映射器字典的简单解决方案:

      vals = df[['a','b','c','d']].to_dict('list')
      mapper = {k: vals[v][k] for k,v in zip(df.index, df['best'])}
      df['value'] = df.index.map(mapper).to_numpy()
      

      输出:

         Date best   a  b   c   d  value
      0  1990    a   5  4   7   2      5
      1  1991    c  10  1   2   0      2
      2  1992    d   2  1   4  12     12
      3  1993    a   5  8  11   6      5
      

      【讨论】:

        【解决方案3】:

        您可以使用np.where 来执行此操作,如下所示。我觉得这样会更有效率

        import numpy as np
        import pandas as pd
        
        df = pd.DataFrame([['1990', 'a', 5, 4, 7, 2], ['1991', 'c', 10, 1, 2, 0], ['1992', 'd', 2, 1, 4, 12], ['1993', 'a', 5, 8, 11, 6]], columns=('Date', 'best', 'a', 'b', 'c', 'd'))
        arr = df.best.values
        
        cols = df.columns[2:]
        for col in cols:
            arr2 = df[col].values
            arr = np.where(arr==col, arr2, arr)
        
        df.drop(columns=cols, inplace=True)
        df["values"] = arr
        df
        

        结果

        Date    best    values
        0   1990    a   5
        1   1991    c   2
        2   1992    d   12
        3   1993    a   5
        

        【讨论】:

          【解决方案4】:

          有一个内置的lookup 函数可以处理这种情况(按行/列查找)。不知道优化到什么程度,但可能比apply方案快。

          In [9]: df['value'] = df.lookup(df.index, df['best'])
          
          In [10]: df
          Out[10]: 
             Date best   a  b   c   d  value
          0  1990    a   5  4   7   2      5
          1  1991    c  10  1   2   0      2
          2  1992    d   2  1   4  12     12
          3  1993    a   5  8  11   6      5
          

          【讨论】:

          • 在toy dataset上apply耗时470us,lookup耗时531us
          • 嗯,由于某种原因,当我在即使是 4000 行的中等大小的 df 上尝试这个时,它也会出现内存错误,对于 400 行,我使用 apply 得到 8.17ms,使用查找得到 3.05ms,所以我希望查找以更好地扩展
          • 由于语法更简单,查找可能更可取,但两者都可以完美运行,谢谢各位!
          • "自 1.2.0 版起已弃用:改用 DataFrame.melt 和 DataFrame.loc。"
          【解决方案5】:

          您创建一个查找函数并在数据帧上按行调用 apply,但这对于大型 dfs 不是很有效

          In [245]:
          
          def lookup(x):
              return x[x.best]
          df['value'] = df.apply(lambda row: lookup(row), axis=1)
          df
          Out[245]:
             Date best   a  b   c   d  value
          0  1990    a   5  4   7   2      5
          1  1991    c  10  1   2   0      2
          2  1992    d   2  1   4  12     12
          3  1993    a   5  8  11   6      5
          

          【讨论】:

          • 你能解释一下这段代码是如何工作的吗?
          • @3kstc 基本上我们使用 apply 通过传递 arg axis=1 来迭代行,所以这里的 lambda 是行所以第一行 x 是第一行,然后我们返回一个特定的列,在这种情况下将是 best 的值来索引该行
          • 注意,对于函数取一行并返回值的情况,您不需要 lambda:df['value'] = df.apply(lookup, axis=1)跨度>
          猜你喜欢
          • 2020-06-08
          • 2022-01-21
          • 2019-02-08
          • 2020-07-18
          • 2016-10-06
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2021-06-17
          相关资源
          最近更新 更多