在 Pandas 1.2.0 或更高版本中通过相应的列标题查找值

Hen*_*ker 9 python dataframe pandas

该操作pandas.DataFrame.lookup“自版本 1.2.0 起已弃用”,并且已使许多以前的答案失效。

这篇文章尝试充当规范资源,用于在 pandas 1.2.0 及更高版本中查找相应的行列对。

具有默认范围索引的标准查找值

给定以下数据框:

df = pd.DataFrame({'Col': ['B', 'A', 'A', 'B'],
                   'A': [1, 2, 3, 4],
                   'B': [5, 6, 7, 8]})
  Col  A  B
0   B  1  5
1   A  2  6
2   A  3  7
3   B  4  8
Run Code Online (Sandbox Code Playgroud)

我希望能够在指定的列中查找相应的值Col

我希望我的结果看起来像:

  Col  A  B  Val
0   B  1  5    5
1   A  2  6    2
2   A  3  7    3
3   B  4  8    8
Run Code Online (Sandbox Code Playgroud)

具有非默认索引的标准查找值

非连续范围索引

给定以下数据框:

df = pd.DataFrame({'Col': ['B', 'A', 'A', 'B'],
                   'A': [1, 2, 3, 4],
                   'B': [5, 6, 7, 8]}, 
                  index=[0, 2, 8, 9])

  Col  A  B
0   B  1  5
2   A  2  6
8   A  3  7
9   B  4  8
Run Code Online (Sandbox Code Playgroud)

我想保留索引但仍然找到正确的对应值:

  Col  A  B  Val
0   B  1  5    5
2   A  2  6    2
8   A  3  7    3
9   B  4  8    8
Run Code Online (Sandbox Code Playgroud)

多重索引

df = pd.DataFrame({'Col': ['B', 'A', 'A', 'B'],
                   'A': [1, 2, 3, 4],
                   'B': [5, 6, 7, 8]},
                  index=pd.MultiIndex.from_product([['C', 'D'], ['E', 'F']]))

    Col  A  B
C E   B  1  5
  F   A  2  6
D E   A  3  7
  F   B  4  8
Run Code Online (Sandbox Code Playgroud)

我想保留索引但仍然找到正确的对应值:

    Col  A  B  Val
C E   B  1  5    5
  F   A  2  6    2
D E   A  3  7    3
  F   B  4  8    8
Run Code Online (Sandbox Code Playgroud)

使用默认值查找不匹配/未找到的值

给定以下数据框

df = pd.DataFrame({'Col': ['B', 'A', 'A', 'C'],
                   'A': [1, 2, 3, 4],
                   'B': [5, 6, 7, 8]})

  Col  A  B
0   B  1  5
1   A  2  6
2   A  3  7
3   C  4  8  # Column C does not correspond with any column
Run Code Online (Sandbox Code Playgroud)

我想查找相应的值(如果存在),否则我希望将其默认为0

  Col  A  B  Val
0   B  1  5    5
1   A  2  6    2
2   A  3  7    3
3   C  4  8    0  # Default value 0 since C does not correspond
Run Code Online (Sandbox Code Playgroud)

查找列中缺少值的查找

给定以下数据框:

   Col  A  B
0    B  1  5
1    A  2  6
2    A  3  7
3  NaN  4  8  # <- Missing Lookup Key
Run Code Online (Sandbox Code Playgroud)

我希望任何NaN值都会Col产生一个NaNVal

   Col  A  B  Val
0    B  1  5  5.0
1    A  2  6  2.0
2    A  3  7  3.0
3  NaN  4  8  NaN  # NaN to indicate missing
Run Code Online (Sandbox Code Playgroud)

Hen*_*ker 10

任何索引的标准查找值

有关按索引/列标签查找值的文档建议使用 NumPy 索引通过factorizereindex作为已弃用的DataFrame.lookup.

import numpy as np
import pandas as pd

df = pd.DataFrame({'Col': ['B', 'A', 'A', 'B'],
                   'A': [1, 2, 3, 4],
                   'B': [5, 6, 7, 8]},
                  index=[0, 2, 8, 9])

idx, col = pd.factorize(df['Col'])
df['Val'] = df.reindex(columns=col).to_numpy()[np.arange(len(df)), idx]
Run Code Online (Sandbox Code Playgroud)

df

  Col  A  B  Val
0   B  1  5    5
1   A  2  6    2
2   A  3  7    3
3   B  4  8    8
Run Code Online (Sandbox Code Playgroud)

factorize用于将列编码值转换为“枚举类型”。

idx, col = pd.factorize(df['Col'])
# idx = array([0, 1, 1, 0], dtype=int64)
# col = Index(['B', 'A'], dtype='object')
Run Code Online (Sandbox Code Playgroud)

请注意B对应于0A对应于1reindex用于确保列的显示顺序与枚举的顺序相同:

df.reindex(columns=col)

   B  A  # B appears First (location 0) A appers second (location 1)
0  5  1
1  6  2
2  7  3
3  8  4
Run Code Online (Sandbox Code Playgroud)

我们需要创建一个与 NumPy 索引兼容的适当范围索引器。

np.arange标准方法是根据 DataFrame 的长度使用:

np.arange(len(df))

[0 1 2 3]
Run Code Online (Sandbox Code Playgroud)

现在 NumPy 索引将用于从 DataFrame 中选择值:

np.arange(len(df))

[0 1 2 3]
Run Code Online (Sandbox Code Playgroud)

*注意:无论索引类型如何,此方法始终有效。

多重索引

df['Val'] = df.reindex(columns=col).to_numpy()[np.arange(len(df)), idx]

[5 2 3 8]
Run Code Online (Sandbox Code Playgroud)
import numpy as np
import pandas as pd

df = pd.DataFrame({'Col': ['B', 'A', 'A', 'B'],
                   'A': [1, 2, 3, 4],
                   'B': [5, 6, 7, 8]},
                  index=pd.MultiIndex.from_product([['C', 'D'], ['E', 'F']]))

idx, col = pd.factorize(df['Col'])
df['Val'] = df.reindex(columns=col).to_numpy()[np.arange(len(df)), idx]
Run Code Online (Sandbox Code Playgroud)

为什么要使用np.arange而不是df.index直接使用呢?

标准连续范围索引

    Col  A  B  Val
C E   B  1  5    5
  F   A  2  6    2
D E   A  3  7    3
  F   B  4  8    8
Run Code Online (Sandbox Code Playgroud)

仅在这种情况下,没有错误,因为结果与np.arange相同df.indexdf

import pandas as pd

df = pd.DataFrame({'Col': ['B', 'A', 'A', 'B'],
                   'A': [1, 2, 3, 4],
                   'B': [5, 6, 7, 8]})

idx, col = pd.factorize(df['Col'])
df['Val'] = df.reindex(columns=col).to_numpy()[df.index, idx]
Run Code Online (Sandbox Code Playgroud)

非连续范围索引错误

引发索引错误:

  Col  A  B  Val
0   B  1  5    5
1   A  2  6    2
2   A  3  7    3
3   B  4  8    8
Run Code Online (Sandbox Code Playgroud)
df = pd.DataFrame({'Col': ['B', 'A', 'A', 'B'],
                   'A': [1, 2, 3, 4],
                   'B': [5, 6, 7, 8]},
                  index=[0, 2, 8, 9])

idx, col = pd.factorize(df['Col'])
df['Val'] = df.reindex(columns=col).to_numpy()[df.index, idx]
Run Code Online (Sandbox Code Playgroud)

多索引错误

df['Val'] = df.reindex(columns=col).to_numpy()[df.index, idx]

IndexError: index 8 is out of bounds for axis 0 with size 4
Run Code Online (Sandbox Code Playgroud)

引发索引错误:

df = pd.DataFrame({'Col': ['B', 'A', 'A', 'B'],
                   'A': [1, 2, 3, 4],
                   'B': [5, 6, 7, 8]},
                  index=pd.MultiIndex.from_product([['C', 'D'], ['E', 'F']]))

idx, col = pd.factorize(df['Col'])
df['Val'] = df.reindex(columns=col).to_numpy()[df.index, idx]
Run Code Online (Sandbox Code Playgroud)

使用默认值查找不匹配/未找到的值

有几种方法。

首先让我们看看如果有不对应的值默认会发生什么:

df['Val'] = df.reindex(columns=col).to_numpy()[df.index, idx]

IndexError: only integers, slices (`:`), ellipsis (`...`), numpy.newaxis (`None`) and integer or boolean arrays are valid indices
Run Code Online (Sandbox Code Playgroud)
import numpy as np
import pandas as pd

df = pd.DataFrame({'Col': ['B', 'A', 'A', 'C'],
                   'A': [1, 2, 3, 4],
                   'B': [5, 6, 7, 8]})
#   Col  A  B
# 0   B  1  5
# 1   A  2  6
# 2   A  3  7
# 3   C  4  8

idx, col = pd.factorize(df['Col'])
df['Val'] = df.reindex(columns=col).to_numpy()[np.arange(len(df)), idx]
Run Code Online (Sandbox Code Playgroud)

如果我们看看为什么NaN引入这些值,我们会发现当遍历factorize列时,它将枚举存在的所有组,无论它们是否对应于列。

因此,当我们使用reindexDataFrame 时,我们最终会得到以下结果:

  Col  A  B  Val
0   B  1  5  5.0
1   A  2  6  2.0
2   A  3  7  3.0
3   C  4  8  NaN  # NaN Represents the Missing Value in C
Run Code Online (Sandbox Code Playgroud)
idx, col = pd.factorize(df['Col'])
df.reindex(columns=col)
Run Code Online (Sandbox Code Playgroud)

如果我们想指定默认值,我们可以指定参数,该fill_value参数reindex允许我们修改与缺失列值相关的行为:

idx = array([0, 1, 1, 2], dtype=int64)
col = Index(['B', 'A', 'C'], dtype='object')
df.reindex(columns=col)
   B  A   C
0  5  1 NaN
1  6  2 NaN
2  7  3 NaN
3  8  4 NaN  # Reindex adds the missing column with the Default `NaN`
Run Code Online (Sandbox Code Playgroud)
idx, col = pd.factorize(df['Col'])
df.reindex(columns=col, fill_value=0)
Run Code Online (Sandbox Code Playgroud)

这意味着我们可以这样做:

idx = array([0, 1, 1, 2], dtype=int64)
col = Index(['B', 'A', 'C'], dtype='object')
df.reindex(columns=col, fill_value=0)
   B  A  C
0  5  1  0
1  6  2  0
2  7  3  0
3  8  4  0  # Notice reindex adds missing column with specified value `0`
Run Code Online (Sandbox Code Playgroud)

df

idx, col = pd.factorize(df['Col'])
df['Val'] = df.reindex(
    columns=col, 
    fill_value=0  # Default value for Missing column values
).to_numpy()[np.arange(len(df)), idx]
Run Code Online (Sandbox Code Playgroud)

*请注意,该dtype列的 是int,因为NaN从未引入,因此列类型未更改。


查找列中缺少值的查找

factorize有一个默认值na_sentinel=-1,这意味着当NaN值出现在被分解的列中时,结果idx值为-1

  Col  A  B  Val
0   B  1  5    5
1   A  2  6    2
2   A  3  7    3
3   C  4  8    0
Run Code Online (Sandbox Code Playgroud)

-1意味着,默认情况下,当我们重新索引时,我们将从最后一列中提取数据。请注意,col仍然仅包含值BA。这意味着我们最终将得到最后A一行的值。Val

处理此问题的最简单方法是使用一些在列标题中找不到的值。fillna Col

这里我使用空字符串''

import numpy as np
import pandas as pd

df = pd.DataFrame({'Col': ['B', 'A', 'A', np.nan],
                   'A': [1, 2, 3, 4],
                   'B': [5, 6, 7, 8]})
#    Col  A  B
# 0    B  1  5
# 1    A  2  6
# 2    A  3  7
# 3  NaN  4  8  # <- Missing Lookup Key

idx, col = pd.factorize(df['Col'])
# idx = array([ 0,  1,  1, -1], dtype=int64)
# col = Index(['B', 'A'], dtype='object')
df['Val'] = df.reindex(columns=col).to_numpy()[np.arange(len(df)), idx]
#    Col  A  B  Val
# 0    B  1  5    5
# 1    A  2  6    2
# 2    A  3  7    3
# 3  NaN  4  8    4 <- Value From A
Run Code Online (Sandbox Code Playgroud)

现在,当我重新索引时,该''列将包含NaN值,这意味着查找会产生所需的结果:

idx, col = pd.factorize(df['Col'].fillna(''))
# idx = array([0, 1, 1, 2], dtype=int64)
# col = Index(['B', 'A', ''], dtype='object')
Run Code Online (Sandbox Code Playgroud)

df

import numpy as np
import pandas as pd

df = pd.DataFrame({'Col': ['B', 'A', 'A', np.nan],
                   'A': [1, 2, 3, 4],
                   'B': [5, 6, 7, 8]})

idx, col = pd.factorize(df['Col'].fillna(''))
df['Val'] = df.reindex(columns=col).to_numpy()[np.arange(len(df)), idx]
Run Code Online (Sandbox Code Playgroud)