使用 pandas (python) 在两列之间进行垂直查找

Vertical lookup between two columns with pandas (python)

我想知道是否可以完成以下table以获得预期的结果(向右)

  X              Y          X              Y
–––––––––––––––-–-        –––––––––––––––-–-
  Argentina     AR          Argentina     AR
  Brazil       NaN          Brazil        BR
  Brazil        BR          Brazil        BR
  Canada        CA          Canada        CA
  NaN           AR          Argentina     AR
  Canada       NaN          Canada        CA

我的意图是通过考虑来自 X 和 Y 列的信息来替换 NaN,特别是为了获得具有副本 country/code 的实例。每个国家只有一个代码,反之亦然。

import pandas as pd
import math
 
data = {
    'X': ['A', 'B', 'B', 'C', None, 'C', 'C'],
    'Y': [1, None, 2, 3, 1, None, 3]
}

df = pd.DataFrame(data)
df_d = df.dropna().drop_duplicates()

for i, val in df.iterrows():
    if pd.isnull(val['X']):
        df.loc[i, 'X'] = df_d.loc[df_d['Y'] == val['Y'], 'X'].values
    if pd.isnull(val['Y']):
        df.loc[i, 'Y'] = df_d.loc[df_d['X'] == val['X'], 'Y'].values
        
print(df)

首先,我复制了原始数据帧,删除了 NaN 值和重复项,只是为了获得唯一行以获取其值。然后遍历原始数据帧中的行并检查其是否 NaN,如果是,则从唯一数据帧中获取值。

   X    Y
0  A  1.0
1  B  2.0
2  B  2.0
3  C  3.0
4  A  1.0
5  C  3.0
6  C  3.0

编辑

  1. 使用 .transform() 的原始答案会因旧而失效 pandas 的版本(例如 1.1.3)。
  2. 有些情况下有人想根据 Y 填充缺失的 X 值,有些情况则相反。
  3. 一个更简单的方法是只得到一个唯一的映射X: Y
def first_valid(g):
    return g.bfill().iloc[0]

m = df.groupby('X')['Y'].apply(first_valid)

>>> m
X
Argentina    AR
Brazil       BR
Canada       CA
Name: Y, dtype: object

如果你愿意,你可以把原来的缺失值补上df,例如如果你有一个更大的 df 和其他列并且想要保持相同的形状,只需填充缺失值:

dct = df.groupby('X')['Y'].apply(first_valid).to_dict()
new_df = df.assign(
    X=df['X'].fillna(df['Y'].map({v:k for k, v in dct.items()})),
    Y=df['Y'].fillna(df['X'].map(dct)),
)