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

时间:2017-10-11 01:34:37

标签: python pandas dataframe data-processing

我正在尝试处理数据帧。这包括创建新列并根据其他列中的值更新其值。更具体地说,我有一个我想要分类的预定义“源”。此来源可以归入三个不同类别'source_dtp','source_dtot'和'source_cash'。我想在数据框中添加三个新列,这些列由原始“源”列的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_id我希望更新其各自的longitudelatitude列 - 基于原始ID(不会像我上面那样迭代,因为它对于大的来说真的很慢)数据集)。

2 个答案:

答案 0 :(得分:3)

另一种方法是在数据框上使用pd.get_dummies。首先放置&_ 39; _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

答案 1 :(得分:1)

您可以使用str.get_dummies获取OHEncodings。

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

接下来,使用c_idpd.concat连接起来。

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