Python 是否有更快的方法根据条件更新数据帧列值?

Python 是否有更快的方法根据条件更新数据帧列值?,python,pandas,dataframe,data-processing,Python,Pandas,Dataframe,Data Processing,我正在尝试处理数据帧。这包括创建新列并基于其他列中的值更新其值。更具体地说,我有一个预定义的“源”,我想分类。该来源可分为三个不同类别:“来源dtp”、“来源dtot”和“来源现金”。我想向dataframe添加三个新列,它们基于原始“源”列由1或0组成 我现在能做到这一点,只是速度很慢 原始柱样: source _id AV4MdG6Ihowv-SKBN_nB DTP AV4Mc2vNhowv-SKBN_Rn Cash 1 AV4Meisi

我正在尝试处理数据帧。这包括创建新列并基于其他列中的值更新其值。更具体地说,我有一个预定义的“源”,我想分类。该来源可分为三个不同类别:“来源dtp”、“来源dtot”和“来源现金”。我想向dataframe添加三个新列,它们基于原始“源”列由1或0组成

我现在能做到这一点,只是速度很慢

原始柱样:

source
_id                     
AV4MdG6Ihowv-SKBN_nB    DTP
AV4Mc2vNhowv-SKBN_Rn    Cash 1
AV4MeisikOpWpLdepWy6    DTP
AV4MeRh6howv-SKBOBOn    Cash 1
AV4Mezwchowv-SKBOB_S    DTOT
AV4MeB7yhowv-SKBOA5b    DTP
期望输出:

source_dtp  source_dtot source_cash
_id         
AV4MdG6Ihowv-SKBN_nB    1.0 0.0 0.0
AV4Mc2vNhowv-SKBN_Rn    0.0 0.0 1.0
AV4MeisikOpWpLdepWy6    1.0 0.0 0.0
AV4MeRh6howv-SKBOBOn    0.0 0.0 1.0
AV4Mezwchowv-SKBOB_S    0.0 1.0 0.0
AV4MeB7yhowv-SKBOA5b    1.0 0.0 0.0
这是我目前的方法,但速度很慢。我更喜欢矢量化的方式,但我不知道怎么做——因为条件非常复杂

# For 'source' we will use the following classes:
source_cats = ['source_dtp', 'source_dtot', 'source_cash']
# [0, 0, 0] would imply 'other', hence no need for a fourth category

# add new features to dataframe, initializing to nan
for cat in source_cats:
    data[cat] = np.nan

for row in data.itertuples():
    # create series to hold the result per row e.g. [1, 0, 0] for `cash`
    cat = [0, 0, 0]
    index = row[0]
    # to string as some entries are numerical
    source_type = str(data.loc[index, 'source']).lower()
    if 'dtp' in source_type:
        cat[0] = 1
    if 'dtot' in source_type:
        cat[1] = 1
    if 'cash' in source_type:
        cat[2] = 1
    data.loc[index, source_cats] = cat
我正在使用itertuples(),因为事实证明它比interrows()快

是否有更快的方法来实现上述功能


编辑:这不仅仅是关于创建一个热编码。它归结为根据另一列的值更新列值。例如,如果我有一个特定的
location\u id
,我想根据原始id更新其各自的
经度
纬度
列(无需像我上面所做的那样迭代,因为它对于大数据集来说非常慢)。

你可以使用
str.get\u dummies
来获取你的编码

c = df.source.str.get_dummies().add_prefix('source_').iloc[:, ::-1]
c.columns = c.columns.str.lower().str.split().str[0]
print(c)
   source_dtp  source_dtot  source_cash
0           1            0            0
1           0            0            1
2           1            0            0
3           0            0            1
4           0            1            0
5           1            0            0
接下来,使用
pd.concat
c
\u id
连接起来

df = pd.concat([df._id, c], 1)
print(df)
                    _id  source_dtp  source_dtot  source_cash
0  AV4MdG6Ihowv-SKBN_nB           1            0            0
1  AV4Mc2vNhowv-SKBN_Rn           0            0            1
2  AV4MeisikOpWpLdepWy6           1            0            0
3  AV4MeRh6howv-SKBOBOn           0            0            1
4  AV4Mezwchowv-SKBOB_S           0            1            0
5  AV4MeB7yhowv-SKBOA5b           1            0            0

改进由于Scott Boston的
set_index
-
reset_index
范例,现在稍微平滑了一些:

df = df.set_index('_id')\
      .source.str.get_dummies().iloc[:, ::-1]
df.columns = df.columns.str.lower().str.split().str[0]
df = df.add_prefix('source_').reset_index()

print(df)
                    _id  source_dtp  source_dtot  source_cash
0  AV4MdG6Ihowv-SKBN_nB           1            0            0
1  AV4Mc2vNhowv-SKBN_Rn           0            0            1
2  AV4MeisikOpWpLdepWy6           1            0            0
3  AV4MeRh6howv-SKBOBOn           0            0            1
4  AV4Mezwchowv-SKBOB_S           0            1            0
5  AV4MeB7yhowv-SKBOA5b           1            0            0

另一种方法是在数据帧上使用。首先将“_id”放入索引中

source = source.set_index('_id')
df_out = pd.get_dummies(source).reset_index()

print(df_out)
输出:

                    _id  source_Cash 1  source_DTOT  source_DTP
0  AV4MdG6Ihowv-SKBN_nB              0            0           1
1  AV4Mc2vNhowv-SKBN_Rn              1            0           0
2  AV4MeisikOpWpLdepWy6              0            0           1
3  AV4MeRh6howv-SKBOBOn              1            0           0
4  AV4Mezwchowv-SKBOB_S              0            1           0
5  AV4MeB7yhowv-SKBOA5b              0            0           1

df.source.str.get_dummies()
将获得0和1。然后,使用
pd.concat
加入您的数据帧,或者只需调用
df.assign
。是的,您可以使用np.where或np.select执行此操作。如果你提出了一个更好的问题,并提供了良好的样本数据和预期的结果,我们Stack Overflow社区将向你展示如何解决。正如@ScottBoston所说,从一开始就提到这一点会很有帮助。您编写所有这些代码来演示MCVE的事实使我们相信它反映了您的实际用例。现在,您需要提供更多的数据和预期输出,以便我们了解您的实际用例以及它与此用例的区别。@vconvo如果您的问题得到了回答,请关闭此问题,并接受我们的一个答案。@coldspeed@Scott Boston我将打开另一个问题-我没想到会有这样一个针对上述问题的具体解决方案(
get_dummies()
)有趣。。。我不能确切地了解条件是如何计算的——1和0是如何分配的?在更复杂的条件下,这将如何实现?@vcovo我不太确定你在问什么,但是
pd.get_dummies
只分配一个热编码,这似乎是你想要的。对于更“复杂的条件”,您需要指定这些条件是什么,以便可以适当地解决它们。让我重新表述一下:data.source.str.get_dummies()如何知道为
[source\u dtp,source\dtot,source\u cash]分配
[0,0,1]
如果
source=“cash 123”
?如果源代码类型中的“现金”
条件在哪里起作用?关于“更复杂的条件”:例如
如果有的话(st in source\u type表示st in cash\u type)
其中
cash\u type
是一个数组,例如
['cash'、'money'、'contant']
@vcovo简单地说,发生的事情是
get\u dummies
找到所有唯一的项,并按顺序为它们分配位置。然后,根据该行的值,为每个条目设置相应的位。对于更复杂的情况,
pd.get\u dummies
在这里不起作用。这是一个仅适用于此用例的特殊函数。对于更复杂的条件,需要更多复杂的方法。假设这是您的实际用例,您可能希望使用反映这一点的MVCE来打开一个新问题!