首页 > 解决方案 > 如何使用 pandas 分配方法优化数据预处理

问题描述

使用熊猫 1.1.4

Matt Harrison 的精彩演讲中,我学会了通过链接方法来预处理数据帧,这对我来说似乎很容易阅读。

在尝试使用链接时,我遇到了一些似乎多余的行。

这是MRE:

df = pd.DataFrame({"st_date":[20210915, 20210914, 20211014, 20211010, 20211014],
                   "language":["python", "python", "python", "java", "java"],
                   "income":[10000, 12000, 11000, 9000, 8000],
                   "next_raise":[2000,4000,3000,2000,1000],
                   "A":[1,2,3,4,5],
                   "B":[3,4,6,7,1]})
def is_weekday(x):
    """1 = weekday"""
    if x <= 4:
        return 1
    else:
        return 0

通常我会通过以下方式进行预处理:

df["st_date"] = pd.to_datetime(df["st_date"], format='%Y%m%d') 
df["dayofweek"] = df["st_date"].dt.dayofweek.astype("int8")
df["weekday"] = df["st_date"].dt.dayofweek.apply(is_weekday).astype(np.int8)

df["raise(%)"] = df["next_raise"] / df["income"] * 100
mean_raise = df["raise(%)"].mean()
df["raise_above_mean"] = np.where(df["raise(%)"] > mean_raise, 1, 0) 

df.drop(columns=["A", "B"], inplace=True)
df[["income", "next_raise"]] = df[["income", "next_raise"]].astype("int16")

链接上述方法变为:

def preprocess(df):
    return (df.assign(dayofweek = df["st_date"].dt.dayofweek.astype("int8"),
                      weekday = df["st_date"].dt.dayofweek.apply(is_weekday).astype(np.int8),
                      raise_p = df["next_raise"] / df["income"] * 100,
                      raise_above_mean = np.where((df["next_raise"] / df["income"] * 100) > #2
                                                  (df["next_raise"] / df["income"] * 100).mean(), 1, 0)
                      )
              .astype({"income":"int16", 
                       "next_raise":"int16"})
              .drop(columns=["A", "B"])
             )

df["st_date"] = pd.to_datetime(df["st_date"], format='%Y%m%d') #1
new_df = preprocess(df)

以下是对我来说似乎多余的行,因此希望使其更有效率。

#1 我想将“st_date”转换为链内的日期时间,当我尝试它时,它似乎在使用之前没有应用,.dt.dayofweek因此输出AttributeError: Can only use .dt accessor with datetimelike values

#2我计算了两次“提高百分比(raise_p)”(3个,包括上面的一个),我该如何避免这种情况?

最后,很高兴知道你们喜欢什么(包括原因):上面的链接或方法。此外,如果您知道更深入地解释使用链接进行预处理的来源,请告诉我!

标签: pythonpandasnumpy

解决方案


您可以将值转换为 中的日期时间assign,但随后需要lambda使用转换列进行处理的函数。同样forweekday是不需要自定义功能,比较Series.le小于或等于。last forraise_above_mean也是必要的lamba功能,因为处理计数列:

def preprocess(df):
    return (df.assign(st_date = pd.to_datetime(df["st_date"], format='%Y%m%d'),
                      dayofweek = lambda x: x["st_date"].dt.dayofweek.astype("int8"),
                      weekday = lambda x: x["st_date"].dt.dayofweek.le(4).astype(np.int8),
                      raise_p = df["next_raise"] / df["income"] * 100,
                      raise_above_mean = lambda x: np.where(x["raise_p"] > x["raise_p"].mean(), 1, 0)
                      )
              .astype({"income":"int16", 
                       "next_raise":"int16"})
              .drop(columns=["A", "B"])
             )

推荐阅读