基于条件,使用不同的替换字典替换pandas数据框列中的值

6

我有一个数据框,我想要替换其中一列中的值,但是描述替换的字典是基于另一列的值的。示例数据框如下:

   Map me strings        date
0       1   test1  2020-01-01
1       2   test2  2020-02-10
2       3   test3  2020-01-01
3       4   test2  2020-03-15

我有一个看起来像这样的字典:

map_dict = {'2020-01-01': {1: 4, 2: 3, 3: 1, 4: 2},
            '2020-02-10': {1: 3, 2: 4, 3: 1, 4: 2},
            '2020-03-15': {1: 3, 2: 2, 3: 1, 4: 4}}

我希望根据日期不同来进行映射逻辑的区分。

在这个例子中,预期输出应该是:

   Map me strings        date
0       4   test1  2020-01-01
1       4   test2  2020-02-10
2       1   test3  2020-01-01
3       4   test2  2020-03-15

我有一个超大的数据框(100M+行),所以我希望尽可能避免任何循环解决方案。
我尝试想出一种使用map或replace的方法,但一直没有成功。

map_dict 中有多少个键? - tmrlvi
大约有800个日期。 - Fredrik Nilsson
循环日期并使用 df.loc 进行赋值怎么样? - tmrlvi
是的,那是我的原始尝试,但它花费了非常非常长的时间,所以我尝试避免任何基于循环的解决方案。 - Fredrik Nilsson
你能添加你原始尝试的代码吗? - tmrlvi
4个回答

7

使用DataFrame.join与由DataFrame构造函数创建的MultiIndex SeriesDataFrame.stack一起:

df = df.join(pd.DataFrame(map_dict).stack().rename('new'), on=['Map me','date'])
print (df)
   Map me strings        date  new
0       1   test1  2020-01-01    4
1       2   test2  2020-02-10    4
2       3   test3  2020-01-01    1
3       4   test2  2020-03-15    4

从性能方面来看,这不是一个很好的解决方案。我的解决方案在850微秒内运行(1000次循环的平均值),而你的解决方案在3.17毫秒内运行(1000次循环的平均值)。 - oskros
是的,我没有尝试使用大型数据集。 - oskros
2
实际上,使用df = pd.concat([df for _ in range(100000)])扩展数据框的结果为47.6毫秒±1.56毫秒,而@oskros的解决方案每个循环需要3.01秒±102毫秒。真是太棒了! - Cainã Max Couto-Silva

1
尝试这样做,也许会有帮助吗?
df['mapped'] = df.apply(lambda x: map_dict[x['date']][x['Map me']], axis=1)

1
这与使用loc循环基本上有什么不同吗?apply不就是一个for循环吗? - Fredrik Nilsson
2
是的,基本上它只是一种更清晰的语法。如果你想让它比这个运行得更快,你可能需要考虑使用 cythonnumba - 你可以尝试遵循这里的指南:Pandas 优化指南 - oskros

1
尝试使用np.where,通常比pandas有更好的性能:
df["Mapped"] = ""
for key in map_dict.keys():
    df["Mapped"] = np.where((df["date"] == key)&(df["Mapped"] == ""), df["Map me"].apply(lambda x: map_dict[key][x]), df["Mapped"])

结果:

    Map me  strings date    Mapped
0   1   test1   2020-01-01  4
1   2   test2   2020-02-10  4
2   3   test3   2020-01-01  1
3   4   test2   2020-03-15  4

0
更像是Pandas的方式是将map_dict转换为DataFrame,然后将其与您的样本框架连接起来。例如:
# Create the original dataframe
>>> df = pd.DataFrame([(1, 'test1', '2020-01-01'), (2, 'test2', '2020-02-10'), (3, 'test3', '2020-01-01'), (4, 'test2', '2020-03-15')], columns=['Map me', 'strings', 'date'])
>>> df
   Map me strings        date
0       1   test1  2020-01-01
1       2   test2  2020-02-10
2       3   test3  2020-01-01
3       4   test2  2020-03-15

# Convert the map dict to a dataframe
>>> map_df = pd.DataFrame([(k, j, l) for k, v in map_dict.items() for j,l in v.items()], columns=['date', 'Map me', 'Map to'])
>>> map_df
          date  Map me  Map to
0   2020-01-01       1       4
1   2020-01-01       2       3
2   2020-01-01       3       1
3   2020-01-01       4       2
4   2020-02-10       1       3
5   2020-02-10       2       4
6   2020-02-10       3       1
7   2020-02-10       4       2
8   2020-03-15       1       3
9   2020-03-15       2       2
10  2020-03-15       3       1
11  2020-03-15       4       4

# Perform the join
>>> mapped_df = pd.merge(df, map_df, left_on=['date', 'Map me'], right_on=['date', 'Map me'])
>>> mapped_df
   Map me strings        date  Map to
0       1   test1  2020-01-01       4
1       2   test2  2020-02-10       4
2       3   test3  2020-01-01       1
3       4   test2  2020-03-15       4
>>> 

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接