Python 多栏标准
我试图根据多列上的某些条件替换Pandas数据框中的值。对于单列标准,这可以通过字典非常优雅地完成,例如: 输入df: 结果df2: 我试图将其扩展到多列上的条件,例如col1==1,col2==10->replace。对于单个标准,可以这样做:Python 多栏标准,python,pandas,Python,Pandas,我试图根据多列上的某些条件替换Pandas数据框中的值。对于单列标准,这可以通过字典非常优雅地完成,例如: 输入df: 结果df2: 我试图将其扩展到多列上的条件,例如col1==1,col2==10->replace。对于单个标准,可以这样做: df3=df.copy() df3.loc[((df['col1']==1)&(df['col2']==10)), 'col1'] = 'c' 这将导致df3: 我在现实生活中遇到的问题有大量的条件,这将涉及大量的df3.loc[criter
df3=df.copy()
df3.loc[((df['col1']==1)&(df['col2']==10)), 'col1'] = 'c'
这将导致df3:
我在现实生活中遇到的问题有大量的条件,这将涉及大量的df3.loc[criteria1&criteria2,column]=值调用,这远不如使用字典作为查找表进行替换。是否可以将优雅的解决方案df2=df.replace{col1:rdict}扩展到一个设置,其中一列中的值由基于多列的条件替换
这是我试图实现的一个例子,尽管在我的现实生活中,标准的数量要大得多:
输入df:
结果df3:
此方法可能比pandas功能更有效,因为它依赖于numpy数组和字典映射
import pandas as pd
df = pd.DataFrame({'col1': {0:1, 1:1, 2:2, 3:2}, 'col2': {0:10, 1:20, 2:10, 3:20}})
rdict = {(1, 10): 'a', (1, 20): 'b', (2, 10): 'c', (2, 20): 'd'}
df['col1'] = list(map(rdict.get, [(x[0], x[1]) for x in df1[['c1', 'c2']].values]))
此方法可能比pandas功能更有效,因为它依赖于numpy数组和字典映射
import pandas as pd
df = pd.DataFrame({'col1': {0:1, 1:1, 2:2, 3:2}, 'col2': {0:10, 1:20, 2:10, 3:20}})
rdict = {(1, 10): 'a', (1, 20): 'b', (2, 10): 'c', (2, 20): 'd'}
df['col1'] = list(map(rdict.get, [(x[0], x[1]) for x in df1[['c1', 'c2']].values]))
演示:
资料来源:
In [120]: df
Out[120]:
col1 col2
0 1 10
1 1 10
2 1 20
3 1 20
4 2 10
5 2 20
6 3 30
条件和替换DF:
In [121]: cond
Out[121]:
col1 col2 repl
1 1 20 b
2 2 10 c
0 1 10 a
3 2 20 d
解决方案:
In [121]: res = df.merge(cond, how='left')
收益率:
In [122]: res
Out[122]:
col1 col2 repl
0 1 10 a
1 1 10 a
2 1 20 b
3 1 20 b
4 2 10 c
5 2 20 d
6 3 30 NaN # <-- NOTE
In [123]: res['col1'] = res.pop('repl').fillna(res['col1'])
In [124]: res
Out[124]:
col1 col2
0 a 10
1 a 10
2 b 20
3 b 20
4 c 10
5 d 20
6 3 30
演示:
资料来源:
In [120]: df
Out[120]:
col1 col2
0 1 10
1 1 10
2 1 20
3 1 20
4 2 10
5 2 20
6 3 30
条件和替换DF:
In [121]: cond
Out[121]:
col1 col2 repl
1 1 20 b
2 2 10 c
0 1 10 a
3 2 20 d
解决方案:
In [121]: res = df.merge(cond, how='left')
收益率:
In [122]: res
Out[122]:
col1 col2 repl
0 1 10 a
1 1 10 a
2 1 20 b
3 1 20 b
4 2 10 c
5 2 20 d
6 3 30 NaN # <-- NOTE
In [123]: res['col1'] = res.pop('repl').fillna(res['col1'])
In [124]: res
Out[124]:
col1 col2
0 a 10
1 a 10
2 b 20
3 b 20
4 c 10
5 d 20
6 3 30
我们可以使用合并
假设您的df看起来像
df = pd.DataFrame({'col1': {0:1, 1:1, 2:2, 3:2, 4:2, 5:1}, 'col2': {0:10, 1:20, 2:10, 3:20, 4: 20, 5:10}})
col1 col2
0 1 10
1 1 20
2 2 10
3 2 20
4 2 20
5 1 10
您的条件替换可以表示为另一个数据帧:
df_replace
col1 col2 val
0 1 10 a
1 1 20 b
2 2 10 c
3 2 20 d
(As OP (Bart) pointed out, you can save this in a csv file.)
然后你可以用
df = df.merge(df_replace, on=["col1", "col2"], how="left")
col1 col2 val
0 1 10 a
1 1 20 b
2 2 10 c
3 2 20 d
4 2 20 d
5 1 10 a
那你只需要放下可乐
正如MaxU所指出的,可能存在无法替换的行,从而导致NaN。我们可以用一条像这样的线
df["val"] = df["val"].combine_first(df["col1"])
如果合并后的结果值为NaN,则填写col1中的值。我们可以使用merge
假设您的df看起来像
df = pd.DataFrame({'col1': {0:1, 1:1, 2:2, 3:2, 4:2, 5:1}, 'col2': {0:10, 1:20, 2:10, 3:20, 4: 20, 5:10}})
col1 col2
0 1 10
1 1 20
2 2 10
3 2 20
4 2 20
5 1 10
您的条件替换可以表示为另一个数据帧:
df_replace
col1 col2 val
0 1 10 a
1 1 20 b
2 2 10 c
3 2 20 d
(As OP (Bart) pointed out, you can save this in a csv file.)
然后你可以用
df = df.merge(df_replace, on=["col1", "col2"], how="left")
col1 col2 val
0 1 10 a
1 1 20 b
2 2 10 c
3 2 20 d
4 2 20 d
5 1 10 a
那你只需要放下可乐
正如MaxU所指出的,可能存在无法替换的行,从而导致NaN。我们可以用一条像这样的线
df["val"] = df["val"].combine_first(df["col1"])
如果合并后的结果值为NaN,则填写col1中的值。能否添加一个可复制的输入数据集和所需的数据集?能否给出一个更接近实际问题的示例数据集?我将更新该问题,以包括一个更现实的问题。能否添加一个可复制的输入数据集和所需的数据集数据集?您能给出一个更接近您的实际问题的示例数据集吗?我将更新该问题以包含一个更现实的问题。这不会产生与df3.loc[df['col1']==1&df['col2']==10,'col1']='c'相同的结果,它只会基于多个标准替换单个列中的值columns@Bart,这个解决方案怎么样?太好了,我喜欢它,因为它使用了与字典相同的方法进行替换,就像用于单列条件的df.replace{col1:rdict}方法一样。我必须看看性能上的差异是否与我的情况有关,如果是的话,这可能是我的首选解决方案。我编写了一个快速基准测试,这实际上似乎是较慢的系数~3.5,请参阅底部的基准测试结果。@Bart,感谢您为基准测试付出的努力。我稍微改变了我的逻辑,使用了一个小的加速。使用df merge方法失败的地方是convert_df的创建。包括convert_df和convert_dict的设置成本,我看到n_行=10000,cats=5的时间非常接近。如果您尝试n_rows=10000,cats=50,我发现convert_df的设置成本比convert_dict低约1.5s~600倍。因此您选择df.merge是正确的,但前提是映射是静态/构建一次/不从csv重复读取。这不会产生与df3.loc[df['col1']==1&df['col2']==10,'col1']='c'相同的结果,它只替换基于一个准则的单个列中的值columns@Bart,那么这个解决方案呢?太好了,我喜欢它,因为它使用了与字典相同的方法进行替换,比如用于单列条件的df.replace{col1:rdict}方法。我必须看看性能上的差异是否与我的情况有关,如果是的话,这可能是我的首选解决方案。我编写了一个快速基准测试,这实际上似乎是较慢的系数~3.5,请参阅底部的基准测试结果。@Bart,感谢您为基准测试付出的努力。我稍微改变了我的逻辑,使用了一个小的加速。使用df merge方法失败的地方是convert_df的创建。包括convert_df和convert_dict的设置成本,我看到n_行=10000,cats=5的时间非常接近。如果尝试n_rows=10000,cats=50,我发现convert_df的设置成本比convert_dict低约1.5s~600倍。因此,使用df.merge是正确的,但前提是映射是静态/构建一次/不重复r
ead来自csv。如前所述,我的实际问题有很多不同的条件,如cond=col1==1和col2==10,不幸的是,我不知道这是如何解决我的问题的。@巴特,好的,你有多个条件,但你有一个或多个替换dict吗?我不确定我是否理解,但你有一个或多个替换dict;我有多个条件,它们都映射到不同的替换值。有趣的解决方案是,如果我将cond建立在定义条件和替换的输入CSV文件上,这可能会很好地工作。我会试一试,除非有人给出一个更优雅的解决方案,否则我会接受这个答案。如前所述,我的现实生活问题有很多不同的条件,比如cond=col1==1和col2==10,不幸的是,我不知道这是如何解决我的问题的。@Bart,好的,你有多个条件,但你有一个或多个替换dict吗?我不知道我是否理解,但你有一个或多个替换dict;我有多个条件,它们都映射到不同的替换值。有趣的解决方案是,如果我将cond建立在定义条件和替换的输入CSV文件上,这可能会很好地工作。我会尝试一下,除非有人发布一个更优雅的解决方案,否则我会接受这个答案。太好了,这会管用的。例如,我可以从定义了条件/替换的CSV文件中创建df_替换,以保持代码干净。@Bart将其保存在另一个CSV文件中是个好主意!让我补充一下。你仍然需要处理那些不会被替换的行…@MaxU这是一个左合并,所以应该可以。df上不匹配的值将被保留。@MaxU,这就是你删除答案的原因吗?这似乎也是一个完美的解决方案。在我的例子中,col1和col2的所有组合都保证是著名的临终遗言。。映射到一个新的值。太好了,这将起作用。例如,我可以从定义了条件/替换的CSV文件中创建df_替换,以保持代码干净。@Bart将其保存在另一个CSV文件中是个好主意!让我补充一下。你仍然需要处理那些不会被替换的行…@MaxU这是一个左合并,所以应该可以。df上不匹配的值将被保留。@MaxU,这就是你删除答案的原因吗?这似乎也是一个完美的解决方案。在我的例子中,col1和col2的所有组合都保证是著名的临终遗言。。映射到新值。