【问题标题】:Reference DataFrame value corresponding to column header参考列标题对应的DataFrame值
【发布时间】:2021-10-28 17:50:26
【问题描述】:

我正在尝试将一个列附加到我的 DataFrame 中,该列基于指定的列名引用的值。

我有以下数据框:

     Area      1         2         3         4      Select     
-----------------------------------------------------------
0      22     54        33        46        23           4       
1      45     36        54        32        14           1        
2      67     34        29        11        14           3       
3      54     35        19        22        45           2        
4      21     27        39        43        22           3   

“选择”下的值引用“选择”显示的列号下的值。比如第0行,“选择”显示4,表示第0行“4”列下的值,即23。然后第1行,“选择”显示1,表示第0行下的值第 1 行中的“1”,即 36。

我想在我的 DataFrame 中添加一个新列,其中包含“Select”所引用的值。

所以我需要使用我的 DataFrame 并创建以下 DataFrame:

     Area      1         2         3         4      Select      Value
----------------------------------------------------------------------
0      22     54        33        46        23           4         23
1      45     36        54        32        14           1         36 
2      67     34        29        11        14           3         11
3      54     35        19        22        45           2         19
4      21     27        39        43        22           3         43  

我不确定如何从“选择”列引用的编号列下提取值,因为列标题只是标题而不是要索引的实际值。这在python中如何实现?

【问题讨论】:

    标签: python pandas dataframe indexing row


    【解决方案1】:

    我们可以使用 Looking up values by index/column labels 上的文档推荐的 numpy 索引来替代已弃用的 DataFrame.lookup

    factorizeSelectreindex

    idx, cols = pd.factorize(df['Select'])
    df['value'] = (
        df.reindex(cols, axis=1).to_numpy()[np.arange(len(df)), idx]
    )
    
    • 注意 1:如果分解列中存在与列标题不对应的值,则结果值为 NaN(表示缺少数据)。

    • 注意 2:两个索引器都需要基于 0 的范围索引(与 numpy 索引兼容)。 np.arange(len(df)) 根据 DataFrame 的长度创建范围索引,因此适用于所有情况。

    但是,如果 DataFrame 已经有兼容的索引(如本例中),则可以直接使用 df.index

    idx, cols = pd.factorize(df['Select'])
    df['value'] = (
        df.reindex(cols, axis=1).to_numpy()[df.index, idx]
    )
    

    df:

       Area   1   2   3   4  Select  value
    0    22  54  33  46  23       4     23
    1    45  36  54  32  14       1     36
    2    67  34  29  11  14       3     11
    3    54  35  19  22  45       2     19
    4    21  27  39  43  22       3     43
    

    另一个选项是Index.get_indexer:

    df['value'] = df.to_numpy()[
        df.index.get_indexer(df.index),
        df.columns.get_indexer(df['Select'])
    ]
    
    • 注意:与上述相同的条件适用,如果df.index 已经是一个连续的基于 0 的索引(与 numpy 索引兼容),我们可以直接使用df.index,而不是使用Index.get_indexer 处理它:
    df['value'] = df.to_numpy()[
        df.index,
        df.columns.get_indexer(df['Select'])
    ]
    

    df:

       Area   1   2   3   4  Select  value
    0    22  54  33  46  23       4     23
    1    45  36  54  32  14       1     36
    2    67  34  29  11  14       3     11
    3    54  35  19  22  45       2     19
    4    21  27  39  43  22       3     43
    

    警告get_indexer:如果Select 中的值与列标题不对应,则返回值为-1,它将返回最后一列的值DataFrame(因为 python 支持相对于末尾的负索引)。这不如NaN 安全,因为它会从Select 列返回一个数值,并且可能很难立即判断数据无效。

    示例程序:

    import pandas as pd
    
    df = pd.DataFrame({
        'Select': ['B', 'A', 'C', 'D'],
        'A': [47, 2, 51, 95],
        'B': [56, 88, 10, 56],
        'C': [70, 73, 59, 56]
    })
    
    df['value'] = df.to_numpy()[
        df.index,
        df.columns.get_indexer(df['Select'])
    ]
    
    print(df)
    

    请注意,最后一行中的 Select 列是 D,但它从 C 中提取值,这是 DataFrame 中的最后一列 (-1)。这并不立即表明查找失败/不正确。

      Select   A   B   C value
    0      B  47  56  70    56
    1      A   2  88  73     2
    2      C  51  10  59    59
    3      D  95  56  56    56  # <- Value from C
    

    factorize比较:

    idx, cols = pd.factorize(df['Select'])
    df['value'] = (
        df.reindex(cols, axis=1).to_numpy()[df.index, idx]
    )
    

    注意最后一行的 Select 列是D,对应的值是 NaN,在 pandas 中用来表示缺失数据。

      Select   A   B   C  value
    0      B  47  56  70   56.0
    1      A   2  88  73    2.0
    2      C  51  10  59   59.0
    3      D  95  56  56    NaN  # <- Missing Data
    

    设置和导入:

    import numpy as np  # (Only needed is using np.arange)
    import pandas as pd
    
    df = pd.DataFrame({
        'Area': [22, 45, 67, 54, 21],
        1: [54, 36, 34, 35, 27],
        2: [33, 54, 29, 19, 39],
        3: [46, 32, 11, 22, 43],
        4: [23, 14, 14, 45, 22],
        'Select': [4, 1, 3, 2, 3]
    })
    

    【讨论】:

      【解决方案2】:

      试试.applyaxis=1。在lambda 中,您可以使用来自Select 列的值来引用该值:

      df["Value"] = df.apply(lambda x: x[x["Select"]], axis=1)
      print(df)
      

      打印:

         Area   1   2   3   4  Select  Value
      0    22  54  33  46  23       4     23
      1    45  36  54  32  14       1     36
      2    67  34  29  11  14       3     11
      3    54  35  19  22  45       2     19
      4    21  27  39  43  22       3     43
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多