我的数据框结构大致如下(它是一个事件参与者列表;池足够小,我们可以假设重复值指的是同一个人):
id_1 id_2 id_3 ... year name country
1_c 2_a 3_a 2011 John France
1_b 2_a 3_c 2010 Jill UK
1_c 2_b 3_c 2018 John Germany
1_c 2_b 3_c 2014 Jason Italy
1_c 2_b 3_b 2017 John Unknown
目的是将“未知”值替换为国家/地区名称,如果该人员在另一年参与其中已知国家/地区。
在极不可能的事件中,他们在不同年份的不同国家/地区上市,我很高兴在最接近“未知”年份的年份中将其列入其中的任何国家(因此,我们将John的'Unknown'改为'Germany'。
我是一个完整的熊猫(和python!)新手。我使用drop_duplicates创建了一个唯一的名称/国家/地区对的列表,但我假设必须有一个更优雅的方式来完成其余的工作,而不是我现在膝盖深处的列表,元组和字典转换的混乱。
答案 0 :(得分:2)
通过pd.DataFrame.apply
可以实现一个非向量化解决方案。这只是一个薄薄的循环。我们循环每一行。如果这个国家不为人知我们:
country
不等于"未知"和name
等于行名。country
最小绝对年差。这是一个完整的例子:
def get_country(row):
if row['country'] != 'Unknown':
return row['country']
else:
res = df.loc[(df['country'] != 'Unknown') & (df['name'] == row['name'])]\
.assign(year_diff=(df['year']-row['year']).abs())
return res.loc[res['year_diff'].idxmin(), 'country'] if not res.empty else 'Unknown'
df['country'] = df.apply(get_country, axis=1)
print(df)
id_1 id_2 id_3 year name country
0 1_c 2_a 3_a 2011 John France
1 1_b 2_a 3_c 2010 Jill UK
2 1_c 2_b 3_c 2018 John Germany
3 1_c 2_b 3_c 2014 Jason Italy
4 1_c 2_b 3_b 2017 John Germany
肯定会有一些聪明的方法来优化使用Pandas / NumPy,例如通过排序。如果考虑性能,则应考虑替代算法。
答案 1 :(得分:0)
这是一种可能性。我认为由于申请,它可能仍然处于缓慢的一方,但如果你有少量独特的名称与行数相比可能会更快:
Unknown
替换为np.NaN pd.Series.interpolate(method='nearest')
NaN
以下是代码:
import pandas as pd
import numpy as np
df = df.replace('Unknown', np.NaN)
df = df.sort_values(['name', 'year']).set_index('year')
dct = dict(zip(df.country[df.country.notnull()].unique(),
range(df.country[df.country.notnull()].nunique())))
inv_dct = {v: k for k, v in dct.items()}
df['country'] = df['country'].map(dct)
df['country'] = df.groupby('name')['country'].apply(
lambda x: x.interpolate(method='nearest').bfill().ffill()
if x.notnull().sum() > 1 else x.bfill().ffill())
df['country'] = df['country'].map(inv_dct)
输出:
id_1 id_2 id_3 name country
year
2014 1_c 2_b 3_c Jason Italy
2010 1_b 2_a 3_c Jill UK
2011 1_c 2_a 3_a John France
2017 1_c 2_b 3_b John Germany
2018 1_c 2_b 3_c John Germany