TowardsDataScience 博客中文翻译 2020(八百一十四)

原文:TowardsDataScience Blog

协议:CC BY-NC-SA 4.0

星巴克顶点挑战

原文:https://towardsdatascience.com/starbucks-capstone-challenge-b95b0931bab4?source=collection_archive---------50-----------------------

这个项目是 Udacity 数据科学纳米学位的一部分

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图片来源: seattle.eater(免费用于商业用途)

介绍

星巴克提供了模拟数据,模拟星巴克奖励移动应用程序上的客户行为。每隔几天,星巴克就会向手机应用程序的用户发出一次报价。优惠可以仅仅是饮料的广告,也可以是实际的优惠,如折扣或 BOGO(买一送一)。某些用户可能在特定的几周内收不到任何优惠。并非所有用户都收到相同的报价,这是这个数据集要解决的挑战。

任务是将交易、人口统计和优惠数据结合起来,以确定哪些人口统计组对哪种优惠类型做出最佳响应。

数据包含在三个文件中:

  • portfolio.json —包含报价 id 和关于每个报价的元数据(持续时间、类型等)。).
  • profile.json —每个客户的人口统计数据。
  • transcript.json 记录交易、收到的报价、查看的报价和完成的报价。

以下是文件中每个变量的模式和解释:

portfolio.json

  • id(字符串)—优惠 id
  • offer_type (string) —优惠的类型,如 BOGO、折扣、信息
  • 难度(int)——完成一项提议所需的最低花费
  • 奖励(int) —为完成一项提议而给予的奖励
  • duration(int)-要约开放的时间,以天为单位
  • 频道(字符串列表)

profile.json

  • 年龄(整数)—客户的年龄
  • 成为会员日期(整数)—客户创建应用程序帐户的日期
  • 性别(str) —客户的性别(请注意,有些条目包含“O”代表其他,而不是 M 或 F)
  • id (str) —客户 id
  • 收入(浮动)—客户的收入

转录本. json

  • 事件(str) —记录描述(即交易、收到的报价、查看的报价等。)
  • 人员(字符串)—客户 id
  • time (int) —测试开始后的时间,以小时为单位。数据开始于时间 t=0
  • value —(字符串字典)—报价 id 或交易金额,具体取决于记录

问题陈述

我选择解决的问题是建立一个模型来预测客户是否会对报价做出反应。

以下是我在分析过程中遵循的主要步骤:

1-探索和清理给定的数据集。

2-组合数据集以获得包含相关特征的最终干净数据。

3-将数据分成训练和测试数据集/缩放特征。

4-选择合适的绩效矩阵。

5-使用 GridSearch 训练分类器并选择最佳估计器

6-计算最佳估计值给出的特征重要性。

7-使用测试数据计算模型的性能,并绘制混淆矩阵。

1-探索和清理给定的数据集

为了理解数据集并揭示初始模式、特征和兴趣点,首先我们需要探索数据集,包括检查缺失值、可视化数据分布等。这样,我们可以看到数据能告诉我们什么,以及如何选择支持模型实现的重要特性。
我们还会做一些预处理,在这一步中,数据会被转换或编码,使其达到机器可以轻松解析的状态。

*# read in the json files*
portfolio = pd.read_json('data/portfolio.json', orient='records', lines=**True**)
profile = pd.read_json('data/profile.json', orient='records', lines=**True**)
transcript = pd.read_json('data/transcript.json', orient='records', lines=**True**)

投资组合数据

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

投资组合的预处理执行如下:

  • 将功能的名称“id”更改为“offer_id”。
  • 将持续时间从一天改为一小时。
  • 将 OneHotEncoding 应用于 channels 列。
  • 将 OneHotEncoding 应用于 offer_type 列。

所有这些步骤都包含在下面的函数中:

**def** clean_portfolio(portfolio):

    *'''*
 *data cleaning the portfolio dataframe*

 *INPUT:*
 *portfolio - the portfolio dataframe to be cleaned*

 *OUTPUT:*
 *portfolio - the cleaned portfolio dataframe*

 *'''*

    *# Change name of feature id to offer_id*
    portfolio.rename(columns={'id': 'offer_id'}, inplace=**True**)

    *# change the duration from day to hour*
    clean_portfolio = portfolio.copy()
    clean_portfolio['duration'] = clean_portfolio['duration'] * 24

    *# apply one hot encoding to channels culumn*

    channels=clean_portfolio['channels'].map(**lambda** x: ','.join(map(str, x))).str.get_dummies(sep=',')

    *# apply one hot encoding to offer_type column*
    offer_type = pd.get_dummies(clean_portfolio['offer_type'])

    *# drop the culumns channels and offer_type* 
    clean_portfolio.drop(['channels', 'offer_type'], axis=1, inplace=**True**)

    *# combine the dataframe clean_portfolio and offer_type to form a cleaned dataframe*
    clean_portfolio = pd.concat([clean_portfolio, channels, offer_type], axis=1, sort=**False**)

    **return** clean_portfolio

将函数应用于投资组合数据集

clean_portfolio=clean_portfolio(portfolio)

清理完数据后,看起来是这样的:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

b 剖面数据

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

绘制年龄分布图

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

从上面的图中,我们可以清楚地看到,年龄为 118 岁的客户在分布图中非常突出,这似乎是异常值。我检查了年龄等于 118 的所有配置文件,它们没有任何性别和收入,年龄为 118 的客户数量为 2175 是不现实的,出于这些原因,我将删除年龄为 118 的所有行。

配置文件的预处理执行如下:

  • 在配置文件数据框中将列 id 的名称更改为 customer_id。
  • 删除年龄在 118 岁以上的客户。
  • 将 OneHotEncoding 应用于特征“性别”。
  • 将特征“年龄”转换为“年龄-十年”,这将有助于确定某一特定年龄是否更受优惠的影响。
  • 将 OneHotEncoding 应用于功能“按年代”。
  • 创建功能“成为成员年”,其中客户从功能“成为成员年”成为成员。
  • 创建功能“成为会员月”,其中客户从功能“成为会员月”成为会员。
  • 创建功能“成为会员日”,其中客户从功能“成为会员日”成为会员。
  • 从“成为会员”功能创建客户的“成为会员”功能。
  • 将 OneHotEncoding 功能应用于“成为 _ 成员 _ 年份”。
  • 将 OneHotEncoding 功能应用于“成了 _ 成员 _ 月”。
  • 将特征“收入”转换为“收入范围”,这将有助于确定某一特定收入范围是否更多地受到报价的影响。
  • 将 OneHotEncoding 功能应用于“income_by_range”。

所有这些步骤都包含在下面的函数中

def clean_profile(profile):

    """ Transforms a DataFrame that contains demographic data for each 
    customer

    INPUT:
        (Optional) data_dir: String that stores the full path to the
                             data directory

    OUTPUT:
        profile: DataFrame that contains demographic data for each 
                 customer
    """
    # copy dataframe from profile to clean_profile
    clean_profile = profile.copy()

    # Change name of culumn id to customer_id in profile dataframe
    clean_profile.rename(columns={'id': 'customer_id'}, inplace=True)

    # Remove customers with age 118
    profile_118 = clean_profile[clean_profile['age'] == 118]
    clean_profile.drop(index=profile_118.index, inplace=True) 

    # OneHotEncoding feature 'gender'
    gender_dummies = pd.get_dummies(clean_profile['gender'], prefix='', prefix_sep='')

    # Convert fetaure 'age' into 'age_by_decade' which would be helpful in determining if a particular age 
    #is influenced more by an offer
    clean_profile['age_by_decade'] = pd.cut(clean_profile['age'], bins=range(10,120,10),right=False, labels=['10s','20s', '30s', '40s', '50s','60s', '70s', '80s', '90s', '100s'])

    # OneHotEncoding feature 'age_by_decade'
    age_dummies = pd.get_dummies(clean_profile['age_by_decade'], prefix='age', prefix_sep='_')

    # Drop feature 'age' 
    clean_profile.drop(columns=['age'], axis=1, inplace=True)

    # Convert type of feature 'became_member_on' to type Datetime
    type(pd.to_datetime(clean_profile['became_member_on'],format='%Y%m%d').dt)# Create feature 'became_member_year' in which customer became member from feature 'became_member_on'
    clean_profile['became_member_year'] = pd.to_datetime(clean_profile['became_member_on'],format='%Y%m%d').dt.year# Create feature 'became_member_month' in which customer became member from feature 'became_member_on'
    clean_profile['became_member_month'] = pd.to_datetime(clean_profile['became_member_on'],format='%Y%m%d').dt.month

    # Create feature 'became_member_day' in which customer became member from feature 'became_member_on'
    clean_profile['became_member_day'] = pd.to_datetime(clean_profile['became_member_on'],format='%Y%m%d').dt.day

    # Create feature 'became_member_tenure' of customers from feature 'became_member_on'
    clean_profile['became_member_tenure'] = (datetime.today().date() - pd.to_datetime(clean_profile['became_member_on'],format='%Y%m%d').dt.date).dt.days# Drop feature 'became_member_on'
    clean_profile.drop(columns=['became_member_on'], axis=1, inplace=True)

    # OneHotEncoding feature 'became_member_year'
    year_dummies = pd.get_dummies(clean_profile['became_member_year'], prefix='', prefix_sep='')# OneHotEncoding feature 'became_member_month'
    month_dummies = pd.get_dummies(clean_profile['became_member_month'], prefix='month', prefix_sep='_')

    # Convert feature 'income' into 'income_by_range' which would be helpful in determining
    # if a particular income range is influenced more by an offer
    clean_profile['income_by_range'] = pd.cut(clean_profile['income'], bins=range(30000,140000,10000), right=False,\
                                    labels=['30ths','40ths', '50ths', '60ths', '70ths','80ths', '90ths',\
                                            '100ths', '110ths', '120ths'])

    # OneHotEncoding feature 'income_by_range'
    income_dummies = pd.get_dummies(clean_profile['income_by_range'], prefix='income', prefix_sep='_')

    # combine the dataframe clean_profile with the different dummies variables
    clean_profile = pd.concat([clean_profile, gender_dummies, age_dummies,year_dummies,month_dummies,income_dummies], axis=1, sort=False)# Return a DataFrame with clean customer profile data
    return clean_profile

将函数应用于数据集配置文件

*# apply the function clean_profile on our dataset 'profile' to  get a cleaned profile*
clean_profile=clean_profile(profile)

这是我们数据集简介的新栏目

*# show the columns of cleaned profile data*
clean_profile.columns

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

显示数据的可视化表示

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

该图显示,在去掉年龄 118 之后,特征年龄是均匀分布的,我们看到大多数消费者的年龄在 40 到 80 岁之间。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

结果表明,大多数顾客在 2017 年加入了星巴克奖励计划,随后在 2018 年加入。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

从上面的图中,我们看到大多数顾客的收入在 30 000 到 90 000 之间。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

剧情描绘了每年加入计划的男性客户比女性客户多。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

从上面的图表中,我们得出结论,男性和女性的最低和最高收入大致相同,但低收入水平的男性顾客数量略高于女性顾客。此外,其他人的收入分配也与男性和女性相似,最低和最高收入低于男性和女性。

c-抄本数据

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

转录本的预处理如下进行:

  • 在副本数据框中,将人物姓名更改为 customer_id。
  • 从副本数据框架中删除年龄为 118 岁的客户的观察结果,因为我们发现年龄为 118 岁的客户是异常值。
  • 创建仅包含优惠事件的数据框 offers_df 和仅包含交易事件的交易 _df。
  • 清理和转换 offers_df 和 transaction_df 数据集。

首先,我们使用下面的函数清理数据集副本

**def** clean_trascript(transcript):

    *'''*
 *data cleaning the transcript dataframe*

 *INPUT:*
 *transcript - the transcript dataframe to be cleaned*

 *OUTPUT:*
 *transcript - the cleaned transcript dataframe*

 *'''*
    *# copy dataframe from transcript to clean_transcript*
    clean_transcript = transcript.copy()

    *# Change name of feature person to customer_id in transcript dataframe*
    clean_transcript.rename(columns={'person': 'customer_id'}, inplace=**True**)

    *# Remove observations having customers with age 118 from transcript dataframe*
    clean_transcript = clean_transcript[~clean_transcript['customer_id'].isin(id_age_118)]    

    **return** clean_transcript

在转录数据集上应用函数

clean_transcript=clean_trascript(transcript)

创建仅包含报价事件的数据帧 offers_df 和仅包含交易事件的交易 _df

*# Create a list of offer event types*
offer_event_list = ['offer received', 'offer viewed', 'offer completed']

*# Find index where feature 'event' is 'offer received', 'offer viewed', 'offer completed'*
offer_index = clean_transcript[clean_transcript['event'].isin(offer_event_list)].index

*# Find index where feature event is 'transaction'*
transaction_index = clean_transcript[~clean_transcript['event'].isin(offer_event_list)].index

*# Create offers_df*
offers_df = clean_transcript.loc[offer_index,:]

*# Create transaction_df*
transaction_df = clean_transcript.loc[transaction_index,:]

这些是我们的新桌子

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

那些桌子似乎需要清洗一下

  • 清洁报价 _df
*# Create another column 'offer_type' with respect to feature 'offer_id'*
offers_df['offer_type'] = offers_df['offer_id'].copy()

offers_df['offer_type'].replace(['ae264e3637204a6fb9bb56bc8210ddfd','4d5c57ea9a6940dd891ad53e9dbe8da0',\
                                 '9b98b8c7a33c4b65b9aebfe6a799e6d9','f19421c1d4aa40978ebb69ca19b0e20d'],\
                                 'bogo', inplace=**True**)

offers_df['offer_type'].replace(['0b1e1539f2cc45b7b9fa7c272da2e1d7','2298d6c36e964ae4a3e7e9706d1fb8c2',\
                                 'fafdcd668e3743c1bb461111dcafc2a4','2906b810c7d4411798c6938adc9daaa5'],\
                                 'discount', inplace=**True**)

offers_df['offer_type'].replace(['3f207df678b143eea3cee63160fa8bed','5a8bc65990b245e5a138643cd4eb9837'],\
                                 'informational', inplace=**True**)
*# Drop feature value as it is not required now and drop feature offer_type as that information is also in portfolio dataframe*
offers_df.drop(columns=['value', 'offer_type'], inplace=**True**)

*# OneHotEncoding feature 'event'*
offers_df = pd.get_dummies(offers_df, columns=['event'], prefix='', prefix_sep='')

*# Reorder columns of offers_df dataframe*
col_order = ['customer_id', 'offer_id', 'time', 'offer received', 'offer viewed', 'offer completed']
offers_df = offers_df.reindex(col_order, axis=1)
  • 清理交易 _df
*# Create column 'amount' in the dataframe transaction_df*
transaction_df['amount'] = transaction_df['value'].apply(**lambda** x: x['amount'])*# Drop'event' and 'value' features*
transaction_df.drop(columns=['event', 'value'], inplace=**True**)

这些是生成的数据集的最终外观(offers_df 和 transaction_df):

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

2-组合数据集以获得包含相关特征的最终干净数据。

下面的函数包括用于组合数据集 clean_portfolip、clean_profile、offers_df 和 transaction_df 的代码。

*# Create function to combine transaction, offer, portfolio and profile datasets*
**def** create_combined_data(portfolio, profile, offers_df, transaction_df):

    *'''Create a combined dataframe from the transaction, demographic and offer data:*
 *INPUT:*
 *portfolio - (dataframe),offer metadata*
 *profile - (dataframe),customer demographic data*
 *offers_df - (dataframe), offers data for customers*
 *transaction_df - (dataframe), transaction data for customers*
 *OUTPUT:*
 *combined_data_df - (dataframe),combined data from transaction, demographic and offer data*
 *'''*

    combined_data = [] *# Initialize empty list for combined data*
    customer_id_list = offers_df['customer_id'].unique().tolist() *# List of unique customers in offers_df*

    *# Iterate over each customer*
    **for** i,cust_id **in** enumerate(customer_id_list):

        *# select customer profile from profile data*
        cust_profile = clean_profile[clean_profile['customer_id'] == cust_id] 

        *# select offers associated with the customer from offers_df*
        cust_offers_data = offers_df[offers_df['customer_id'] == cust_id]

        *# select transactions associated with the customer from transactions_df*
        cust_transaction_df = transaction_df[transaction_df['customer_id'] == cust_id]

        *# select received, completed, viewed offer data from customer offers*
        offer_received_data  = cust_offers_data[cust_offers_data['offer received'] == 1]
        offer_viewed_data = cust_offers_data[cust_offers_data['offer viewed'] == 1]
        offer_completed_data = cust_offers_data[cust_offers_data['offer completed'] == 1]

        *# Iterate over each offer received by a customer*
        rows = [] *# Initialize empty list for a customer records*

        **for** off_id **in** offer_received_data['offer_id'].values.tolist():

            *# select duration of a particular offer_id*
            duration = clean_portfolio.loc[clean_portfolio['offer_id'] == off_id, 'duration'].values[0]

            *# select the time when offer was received*
            off_recd_time = offer_received_data.loc[offer_received_data['offer_id'] == off_id, 'time'].values[0]

            *# Calculate the time when the offer ends*
            off_end_time = off_recd_time + duration

            *#Initialize a boolean array that determines if the customer viewed an offer between offer period*
            offers_viewed = np.logical_and(offer_viewed_data['time'] >= off_recd_time,offer_viewed_data['time'] <= off_end_time)

            *# Check if the offer type is 'bogo' or 'discount'*
            **if** (clean_portfolio[clean_portfolio['offer_id'] == off_id]['bogo'].values[0] == 1 **or**\
                    clean_portfolio[clean_portfolio['offer_id'] == off_id]['discount'].values[0] == 1):

                *#Initialize a boolean array that determines if the customer completed an offer between offer period*
                offers_comp = np.logical_and(offer_completed_data ['time'] >= off_recd_time,\
                                                 offer_completed_data ['time'] <= off_end_time)

                *#Initialize a boolean array that selects customer transctions between offer period*
                cust_tran_within_period = cust_transaction_df[np.logical_and(cust_transaction_df['time'] >= off_recd_time,\
                                                                                 cust_transaction_df['time'] <= off_end_time)]

                *# Determine if the customer responded to an offer(bogo or discount) or not*
                cust_response = np.logical_and(offers_viewed.sum() > 0, offers_comp.sum() > 0) **and**\
                                                    (cust_tran_within_period['amount'].sum() >=\
                                                     clean_portfolio[clean_portfolio['offer_id'] == off_id]['difficulty'].values[0])

            *# Check if the offer type is 'informational'*
            **elif** clean_portfolio[clean_portfolio['offer_id'] == off_id]['informational'].values[0] == 1:

                *#Initialize a boolean array that determines if the customer made any transctions between offer period*
                cust_info_tran = np.logical_and(cust_transaction_df['time'] >= off_recd_time,\
                                                    cust_transaction_df['time'] <= off_end_time)                   

                *# Determine if the customer responded to an offer(informational) or not*
                cust_response = offers_viewed.sum() > 0 **and** cust_info_tran.sum() > 0                  

                *#Initialize a boolean array that selects customer transctions between offer period*
                cust_tran_within_period = cust_transaction_df[np.logical_and(cust_transaction_df['time'] >= off_recd_time,\
                                                                                 cust_transaction_df['time'] <= off_end_time)]

            *# Initialize a dictionary for a customer with required information for a particular offer*
            cust_rec = {'cust_response': int(cust_response),'time': off_recd_time,'total_amount': cust_tran_within_period['amount'].sum()}
            cust_rec.update(clean_profile[clean_profile['customer_id'] == cust_id].squeeze().to_dict())
            cust_rec.update(clean_portfolio[clean_portfolio['offer_id'] == off_id].squeeze().to_dict())

            *# Add the dictionary to list for combined_data*
            rows.append(cust_rec)

        *# Add the dictionaries from rows list to combined_data list*
        combined_data.extend(rows)

    *# Convert combined_data list to dataframe*
    combined_data_df = pd.DataFrame(combined_data)

    *# Reorder columns of combined_data_df*
    combined_data_df_col_order = ['customer_id', 'offer_id', 'time']

    port_ls = clean_portfolio.columns.tolist()
    port_ls.remove('offer_id')
    pro_ls = clean_profile.columns.tolist()
    pro_ls.remove('customer_id')
    combined_data_df_col_order.extend(port_ls)
    combined_data_df_col_order.extend(pro_ls)
    combined_data_df_col_order.extend(['total_amount', 'cust_response'])

    combined_data_df = combined_data_df.reindex(combined_data_df_col_order, axis=1)
    combined_data_df.to_csv('combined_data2.csv', index=**False**)
    **return** combined_data_df

以下是组合数据的特征:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

创建一个名为 offer_success 的数据框,其特征为 offer_id、count、success_pourcentage 和 offer_type,以建立出价之间的比较。

**def** calculate_percentage_success():

    *'''Create dataframe offer_success with features offer_id, success_pourcentage and offer_type*

 *OUTPUT:*
 *offer_response - (dataframe), with the features offer_id, success_pourcentage and offer_type*
 *'''*

    *#* 
    offer_response = combined_data_df.groupby(['offer_id'])['cust_response'].count().reset_index()
    offer_response.rename(columns={'cust_response': 'count'}, inplace=**True**)
    success_pourcentage = combined_data_df.groupby(['offer_id'])['cust_response'].sum()/\
                combined_data_df.groupby(['offer_id'])['cust_response'].count()
    np.round(success_pourcentage.values*100,2)
    offer_response['success_pourcentage'] = np.round(success_pourcentage.values*100,2)                                  
    offer_response['offer_type'] = offer_response['offer_id'].map({'ae264e3637204a6fb9bb56bc8210ddfd': 'bogo',\
                                                               '4d5c57ea9a6940dd891ad53e9dbe8da0': 'bogo',\
                                                               '3f207df678b143eea3cee63160fa8bed': 'informational',\
                                                               '9b98b8c7a33c4b65b9aebfe6a799e6d9': 'bogo',\
                                                               '0b1e1539f2cc45b7b9fa7c272da2e1d7': 'discount',\
                                                               '2298d6c36e964ae4a3e7e9706d1fb8c2': 'discount',\
                                                               'fafdcd668e3743c1bb461111dcafc2a4': 'discount',\
                                                               '5a8bc65990b245e5a138643cd4eb9837': 'informational',\
                                                               'f19421c1d4aa40978ebb69ca19b0e20d': 'bogo',\
                                                               '2906b810c7d4411798c6938adc9daaa5': 'discount'})

    offer_response=offer_response.sort_values(by=['success_pourcentage'], ascending=**False**)
    **return** offer_response

这是数据集 offer_success

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

绘制两个条形图,一个到显示了有多少客户获得了特定的报价,另一个显示了每次报价的成功率。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

从上面显示的结果中,我们注意到发送给客户的报价数量几乎相同。
对于要约的成功率,我们观察到 10 号和 2 号要约最成功,成功率分别为 75.20%和 72.28%,最低的是 4 号要约,成功率为 36.76%。

  • 获得准备好的数据集的最后一步是清除无用的要素。
*# Drop features from combined_data which are not required for training the model*
combined_data_df.drop(columns=['customer_id', 'offer_id', 'time', 'email','gender', 'income', 'age_by_decade','became_member_year',
'became_member_month', 'became_member_day','income_by_range'], inplace=**True**)

清洗后,我们得到上面的列:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

3-将数据分成训练和测试数据集/缩放特征

我们使用的数据通常分为训练数据和测试数据。训练集包含一个已知的输出,模型学习这个数据,以便以后推广到其他数据。我们有测试数据集来测试我们的模型对这个子集的预测。

*# features : independece variables that act as the input of the model*
X = combined_data_df.drop(columns=['cust_response'])
*# target : the variable to predict* 
y = combined_data_df['cust_response'
*# split data into train and test sets*
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42)

然后,我们继续进行特征缩放,这是一种使用最小最大缩放器来归一化独立变量范围或数据特征的方法。

准备要缩放的要素列表

*# Prepare list of features to scale*
features_to_scale = ['difficulty', 'duration', 'reward', 'became_member_tenure', 'total_amount']

然后是缩放要素的函数

**def** features_scale(df, feat=features_to_scale):

    *"""*
 *Scale list features in a given dataframe*

 *INPUT:*
 *- df (dataframe): dataframe having features to scale*
 *- feat (list): list of features in dataframe to scale*

 *OUTPUT:*
 *- scaled_df (dataframe): dataframe containing scaled features*
 *"""*

    *# Prepare dataframe with features to scale*
    df_feat_scale = df[feat]

    *# Apply feature scaling to df*
    scaler = MinMaxScaler()
    df_feat_scale = pd.DataFrame(scaler.fit_transform(df_feat_scale), columns = df_feat_scale.columns,index=df_feat_scale.index)

    *# Drop orignal features from df and add scaled features* 
    df = df.drop(columns=feat, axis=1)
    df_scaled = pd.concat([df, df_feat_scale], axis=1)

    **return** df_scaled

将函数应用于要素

*# Scale selected features in training set i.e. X_train*
X_train_scaled = features_scale(X_train, feat=features_to_scale)

计算目标类在训练集中的分布百分比

round((y_train.squeeze().value_counts()/y_train.squeeze().count())*100,2)

输出

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

从上面显示的结果中,我们可以观察到我们的训练数据集几乎是平衡的,响应报价的客户数量(53.8%)和未响应报价的客户数量(46.2%)几乎相等。因为,我们的训练数据集几乎是平衡的,我们不需要处理技术来对抗类别不平衡。

4-选择适当的绩效矩阵

我们发现,我们的训练数据在目标类的分布方面几乎是平衡的,精度、召回率和 f1_score 等性能指标是评估模型的完美度量。F1 得分指标是“精确度和召回率指标的调和平均值”,是一种更好的方法,可以提供更强的问题预测能力以及预测模型的预测能力。

5-使用 GridSearch 训练分类器并选择最佳估计器

下面的函数将使用 k-fold 交叉验证来拟合分类器,并计算 f1 值

**def** fit_classifier(clf, param_grid, X=X_train_scaled.values, y=y_train.squeeze().values):

    *"""*
 *Fits a classifier to its training data using GridSearchCV and calculates f1_score*

 *INPUT:*
 *- clf (classifier): classifier to fit*
 *- param_grid (dict): classifier parameters used with GridSearchCV*
 *- X_train_scaled (DataFrame): training features*
 *- y_train (DataFrame): training label*

 *OUTPUT:*
 *- classifier: input classifier fitted to the training data*
 *"""*

    *# cv uses StratifiedKFold*
    *# scoring f1 available as parameter*
    start = time.time()
    grid = GridSearchCV(estimator=clf, param_grid=param_grid, scoring='f1', cv=5, verbose=0)
    print("Training **{}** :".format(clf.__class__.__name__))
    grid.fit(X, y)
    end = time.time()
    time_taken = round(end-start,2)

    print(clf.__class__.__name__)
    print("Time taken : **{}** secs".format(time_taken))
    print("Best f1_score : **{}**".format(round(grid.best_score_,4)))
    print("*"*40)

    **return** grid.best_score_, grid.best_estimator_, time_taken

初始化分类算法

lr = LogisticRegression(random_state=42) *# LogisticRegression*
rfc = RandomForestClassifier(random_state=42) *# RandomForestClassifier*
gbc = GradientBoostingClassifier(random_state=42) *# GradientBoostingClassifier*
abc = AdaBoostClassifier(random_state=42) *# AdaBoostClassifier*

寻找最佳分类算法

cl_names = []
cl_scores = []
cl_best_ests = []
cl_time_taken = []
cl_dict = {}

**for** classifier **in** [lr, rfc, abc, gbc]:
    best_score, best_est, time_taken = fit_classifier(classifier, {})
    cl_names.append(classifier.__class__.__name__)
    cl_scores.append(best_score)
    cl_best_ests.append(best_est)
    cl_time_taken.append(time_taken)

输出

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

RandomForestClassifier 和 GradientBoostingClassifier 的 f1_score 几乎相等(大约。0.92),但 RandomForestClassifier 比 GradientBoostingClassifier 花费的训练时间要少得多。因此,上述 4 种分类器中性能最好的分类器算法是 RandomForestClassifier。

  • 然后,我们可以借助 GridSearchCV 中的 param 网格来调整 RandomForestClassifier 分类器。
*# Tuninig RandomForestClassifier classifier with the help of param grid in GridSearchCV*
param_grid = {
               *# Number of trees in random forest*
              'n_estimators': [10, 50, 80, 100],
               *# Maximum number of levels in tree*
              'max_depth': [**None**],
               *# Minimum number of samples required to split a node*
              'min_samples_split': [2, 5, 10],
               *# Minimum number of samples required at each leaf node*
              'min_samples_leaf': [1, 2, 4]}

rfc = RandomForestClassifier(random_state=42)
rfc_best_score, rfc_best_est, _ = fit_classifier(rfc, param_grid)
rfc_best_est

调整后,我们获得了以下结果:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

为了选择要调整的超参数,我们进行了彻底的网格搜索,它接受许多超参数,并尝试超参数的每一个可能的组合以及我们希望它执行的许多交叉验证(这里我们选择 cv=5)。彻底的网格搜索是确定要使用的最佳超参数值的好方法,但是随着我们添加每个额外的参数值和交叉验证,它会很快变得非常耗时。

我们选择调整的参数是:min_samples_leaf、min_samples_split、n_estimators、max_depth。在调整之前,这些参数的值是 max_depth=None,min_samples_leaf=1,min_samples_split=2,n_estimators=10。

上面显示的代码运行了 20 多分钟,但选择的超参数在预测训练模型时有 92.94%的准确性。得到的“最佳”超参数如下:min_samples_leaf = 1,min_samples_split = 2,n_estimators = 100,max_depth=None。

仔细而有条理地调整超参数可能是有利的。它可以使我们的分类模型更准确,这将导致总体上更准确的预测。

我们注意到,在对训练好的 RandomForestClassifier 进行微调之后,我们得到了更好的 f1 _ score 0.9294,而在调整之前它是 0.9196,因此我们可以观察进度。

6-计算最佳估计值给出的特性重要性

通过 RandomForestClassifier 准备包含要素及其重要性的数据框

feature_imp = pd.DataFrame(rfc_best_est.feature_importances_,index=X_train_scaled.columns.tolist(),columns=['feat_imp']).reset_index()

feature_imp.rename(columns={'index': 'feature'}, inplace=**True**)
feature_imp['feat_imp_rate'] = np.round((feature_imp['feat_imp']/feature_imp['feat_imp'].sum())*100,2)
feature_imp = feature_imp.sort_values(by=['feat_imp_rate'], ascending=**False**).reset_index(drop=**True**)
feature_imp.drop(columns=['feat_imp'],inplace=**True**)
feature_imp

绘制特征及其重要性的条形图

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

从上面显示的结果中,我们注意到:

影响客户在查看报价后是否会对报价做出回应的 4 大特征是:

  • 客户花费的总金额是最重要的特征,它几乎不会影响客户在查看报价后是否会完成报价。
  • “成为会员任期”是第二大特征,它代表了顾客成为星巴克奖励计划会员的时间长短,对顾客是否会在回应后完成报价有很大影响。
  • “社交功能”表示,如果星巴克通过社交媒体向顾客发送报价,可能会比其他沟通方式得到更多回应。
  • “难度”特征,表示如果客户响应并完成报价,完成报价所需的最小花费金额。

7-使用测试数据计算模型的性能,并绘制混淆矩阵

  • 计算预测
*# Classification of test data using best model trained on train data*
predictions = rfc_best_est.predict(X_test_scaled)
  • 绘制归一化混淆矩阵

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

结果表明,有 4%的百分比错误分类客户接受要约和 11%的错误分类客户拒绝要约。由于假阴性比假阳性少,我们的预测模型做得很好,因为它错过会响应的个体的机会非常低。

由于 Starbucks 不希望错过向愿意回应的个人发送报价,因此该模型适合这种情况,因为它不会错过向愿意回应的个人发送报价。此外,星巴克不会介意向一些不会回复的人发送报价,因为他们已经覆盖了所有会回复的人。因此,我们的预测模型在这种情况下会工作得很好。

结论

我选择解决的问题是建立一个模型来预测客户是否会对报价做出反应。我解决这个问题的策略主要有三个步骤。首先,在预处理投资组合、配置文件和交易数据集之后,我将它们组合起来,以获得包含相关特征的最终干净数据,该数据可用于训练我们的模型。其次,在分割数据以训练和测试数据集之后,我们使用 GridSearch 选择了最佳估计器“RandomForestClassifier ”,这是上述 4 个测试的分类器中性能最好的分类器算法(我比较了 F1 分数和所用时间)。第三,我使用测试数据预测测试目标,并绘制混淆矩阵以确保我们的模型的性能,我们发现我们的预测模型非常适合这种情况。

我喜欢在这个项目中工作,这让我可以在一个真实的项目中工作。这个项目最有趣的方面是结合不同的数据集,并使用预测建模技术和分析来为业务提供更好的决策和价值。争吵是最长也是最具挑战性的部分。整个分析中最困难的部分是找到逻辑和策略来创建一个组合数据集,并决定问题陈述。

丰富

  • 如果有更多的客户指标,可能会有更好的预测。对于这一分析,我觉得我们所掌握的客户信息有限,只有年龄、性别和收入。为了找到最佳的客户统计数据,最好能有更多的客户特征。这些附加特征可以帮助提供更好的分类模型结果数据,以便具有更好的模型。
  • 此外,最初看起来我们有很多数据要处理,但是一旦删除了 NaN 值和重复的列,并将数据合并到一个单独的数据集中,就好像模型可能会从更多的数据中受益。有了更多的数据,分类模型可能已经能够产生更好的 F1 分数结果。
  • 另外,我们可以通过另一个问题陈述来改进这个项目,我们可以建立一个模型来预测哪些人口统计群体会购买,即使他们没有收到报价。

请注意,文章讨论的是分析的重要代码,你可以在这里找到星巴克顶点挑战项目的完整代码。

使用 CatBoost 和散景的星巴克顾客特征分析

原文:https://towardsdatascience.com/starbucks-customer-classification-using-catboost-c3026d1785d7?source=collection_archive---------20-----------------------

多类 | 活页夹

使用客户旅程和多类分类的解决方案

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

TRUnsplash 上拍照

介绍

在这篇文章中,我探索了由 StarbucksUdacity 合作提供的客户数据,以了解客户在潜在回报方面的行为。星巴克的移动应用程序向其顾客发送不同种类的激励优惠,以保持他们对该品牌的参与。

这篇文章的动机是讨论一种用来分析预测客户响应的数据和机器学习解决方案的解决方案。

我使用机器学习库 CatBoost 来解决多类分类问题,并使用散景作为主要的可视化工具。

该项目的 GitHub Repo 可以在这里找到。

1.概观

该数据集包含模拟星巴克奖励移动应用程序上的客户行为的模拟数据。每隔几天,星巴克就会向手机应用程序的用户发出一次报价。优惠可以仅仅是饮料的广告,也可以是实际的优惠,例如折扣或 BOGO(买一送一)。某些用户可能在特定的几周内收不到任何优惠。

在要约到期之前,每个要约都有一个有效期。例如,BOGO 的报价可能只有五天的有效期。你会在数据集中看到,信息优惠有一个有效期,即使这些广告仅仅是提供关于产品的信息;例如,如果信息性报价有七天的有效期,您可以假设客户在收到广告后的七天内感受到了报价的影响。

【项目概述摘自 Udacity 的顶点项目 数据科学纳米学位项目

数据集

数据包含在三个文件中:

portfolio.json —包含要约 id 和关于每个要约的元数据(持续时间、类型)

profile.json —每个客户的人口统计数据

抄本. json —交易记录、收到的报价、查看的报价和完成的报价

2.问题陈述

目的是分析单个客户的行为,以识别不寻常的模式。这种分析的发现应该有助于星巴克企业根据具体结果重新评估其奖励计划。

我旨在针对以下业务问题提供分析:

  • 我们可以根据客户的响应能力对他们进行分类吗?
  • 我们能否识别不关心奖励计划的高收入客户?
  • 我们能否确定过去没有任何交易的客户?
  • 我们能否可视化客户与优惠和消费活动的互动,以获得有趣的见解?

3.解决方案概念

  • 有三个不同的数据集,我逐一研究并识别任何问题,如缺失信息、额外/冗余信息、其他不一致。我通过在必要时充分利用视觉化来实现这一点。在这一步的最后,我有了一个干净的数据集,可以做进一步的探索。
  • 我将所有三个数据集合并成一个数据集,并通过高级可视化进行进一步分析。基于此,我构建了一个分类问题,通过一些机器学习算法来解决。
  • 我选择了 CatBoost 算法,一种多类分类算法。它自动识别高度相关的特征之间的关系,并带有内置的可视化功能。使用它训练和评估模型是简单的。使用默认参数的最终结果通常会更好,因为 CatBoots 在内部使用水平决策树。由于我们正在处理分类问题,并且错误分类的错误不会导致任何不利影响,在这种情况下,模型准确性应该是我们的标准评估标准,包括混淆矩阵。
  • 最后,我对整体分析的结果进行评估,包括机器学习模型的评估。

4.数据探索和基本可视化

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

投资组合数据集预览

  • 通过查看“通道”列,将每个通道值分解到单独的列中并使用 0|1 标识符对其进行编码是有意义的。
  • 让我们为“offer_type”列创建虚拟列,对其进行编码,并删除原来的列,因为我们不再需要它。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

清理后的投资组合数据集

在这里,每个报价总是通过“电子邮件”渠道发送。因此,该特征仅提供信息,并且可能不会给任何机器学习算法的预测能力增加任何价值。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

配置文件数据集预览

显然,“年龄”值 118 是缺失值的占位符。进一步的分析显示,性别、年龄和收入栏总共有 2175 个缺失条目。

“成为会员”列是一个带有时间戳的日期,让我们将其转换为可读性更好的格式,并提取自客户注册以来的天数。

让我们创建一些可视化工具来分析人口统计数据

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

顾客年龄分布

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

按年份统计的客户注册数

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

客户收入分配

左图显示了这些年来客户数量的稳步增长。然而,在 2017 年底有一个陡峭的下降。这也可能是由于准备数据集的采样。

令人惊讶的是,属于相对较低收入群体的客户很多,属于相对较高收入群体的客户很少。

配对图显示,女性客户不多,女性群体年龄相对较大,收入较高。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

人口统计数据对图表

具体观察结果

  • 年龄组[20,30]中没有收入高于 80K 的客户。
  • 在[40,50]年龄组中,没有收入高于 10 万英镑的客户。
  • 所有 2000 多天前成为会员的客户收入都低于 10 万。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

成绩单数据集预览

快速查看一下脚本数据集,就会发现“value”列被编码为一个字典。如果事件与报价相关,则“值”列编码报价 id,如果是交易事件,则编码交易金额。

因此,将“价值”列解码为单独的列,以了解优惠和客户花费的金额之间的关系是有意义的。

5.数据预处理和高级可视化

首先要计算完成的总报价数和每个客户查看的总报价数。
这些数据包括客户有意或无意的“完成的报价”。不应向不知情已完成报价的客户发送进一步的报价。这个群体代表了公司的盈利客户。

我们将我们的成绩单数据集与客户人口统计数据(个人资料)和投资组合数据相结合。

在应用于联合数据集的几个预处理步骤之后,

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

按时间线查看的出价数([0–714])

上图显示了根据时间戳查看的报价数量(以小时为单位)。在六个峰值中,浏览报价的数量急剧增加。

我已经在图表中嵌入了收到的报价数(正确的收到报价数是标记数的四倍)。当收到新的报价时,已查看报价的数量会增加,然后随着时间的推移慢慢减少。一般来说,大多数优惠都是在收到后 24 小时内查看的。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

根据时间表完成的出价数([0–714])

上图显示了以小时为单位的时间戳中已完成的报价数量。它遵循与之前图表相似的模式,因为新报价在 24 天内发送了 6 次,因此图表有 6 个峰值。

在每个峰值之间,图表逐渐减小,就像查看报价图表一样。然而,下降并不像查看报价图那样平稳。下跌期间有一些地方选股。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

显示交易数量和按时间表完成的报价的联合图表

上面的图表结合了一些交易和报价一起完成。在交易的每个“报价发送间隔”之间有一个局部峰值。这意味着当收到报价时,客户会快速执行一些交易,从而完成报价。

在时间戳 0 处,存在大约 600 个事务。其中大约 200 个有助于“要约完成”(时间戳为 0 时完成的要约数量),这大约是 25%的转化率。这个数字与已完成要约总数与交易总数的比值=> 138953/33579)*100 = 24.16%大致吻合。

存在一些高价值交易(100 美元以上)。这可能是个人为特殊活动或公司客户的大订单。这样的高价值交易导致与客户相关联的所有当前报价被完成。

在现实中,这些交易并没有完成要约的动机,因此应被视为副作用。向如此高收入的客户发出报价不会导致他们购买行为的增加或减少。因此,我们应该从数据集中删除这样的高价值交易。

接下来,我们还应该找出并清除不响应的客户。我定义无响应客户=未收到报价、未查看+未达成交易。

在一些进一步的预处理步骤之后,我发现有 422 个客户没有进行交易。其中,412 人收到并查看了报价,10 人收到但未查看任何报价。

同样,在分析交易金额时,收集了以下观察结果:

  • 有些交易超过 1000 美元。
  • 范围[0.05,50]内的事务比该范围内的其他事务多得多。
  • 任何超过 50 美元的交易都可以被视为高价值交易,不一定有动机完成报价。

6.通过客户之旅进行特征工程

在本节中,我们将通过一些高级的可视化方式来了解顾客与产品的互动。基于此,我定义了一些计算特征。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

客户旅程(id:“6 E0”)

在上面的图表中,我们有一个客户,他/她已经完成了发送给他/她的所有报价。如果这些交易的价值较低,通常需要一次以上的交易才能完成要约。

有时,客户会立即查看报价,而有时,他/她会在稍后时间查看。

在完成的 4 个报价中,只有 1 个(最后完成的)未被客户查看。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

两位高价值客户的并肩之旅

在这里,我们有两个高付费客户并排完成了所有收到的报价。

有趣的是,对于客户“9fa ”,在完成第一次报价后,他/她已经进行了五次交易,总计约 75 美元,没有任何待完成的报价。它表明,这些交易没有动机完成报价,并显示客户在没有任何报价的情况下的消费倾向。

基于以上分析我推导出以下自定义特性
1。给定客户完成报价的百分比
2。给定客户完成的报价绝对计数
3。给定客户查看的优惠的百分比
4。给定客户查看的优惠的绝对数量
5。给定客户的总消费金额

7.模型训练+评估

注意事项:

我们的问题属于多类分类的范畴。多类分类问题可以总结如下:

给定一个数据集,该数据集具有𝑥𝑖和𝑁类的实例,其中每个𝑥𝑖实例都精确地属于一个类,𝑦𝑖是多类分类器的目标问题。
在训练和测试之后,对于测试集中的每个实例𝑥𝑖,我们有一个具有正确类别𝑦𝑖和预测类别𝑎𝑖的表。因此,对于每个实例,我们要么匹配(𝑦𝑖=𝑎𝑖),要么不匹配(𝑦𝑖≠𝑎𝑖).
然而,F1-score 也可以用于多类问题的评估。

由于在我们的案例中,错误分类的成本并不高(向没有响应的客户发送报价不会给公司带来额外的成本),因此 F1-分数是不必要的。

在这个项目中,我更喜欢使用混淆矩阵和平均分作为我们的评估指标。 混淆矩阵: 一个混淆矩阵显示了实际和预测类的组合。矩阵的每一行代表预测类中的实例,而每一列代表实际类中的实例。这是一个很好的方法来衡量模型是否能解释类属性的重叠,并理解哪些类最容易混淆。

准确率:
分类正确的项目总数百分比- (TP+TN)/(N+P)
TP:真正
TN:真负
N:负
P:正

对于不平衡的类分布,我已经给每个类标签提供了权重,CatBoost 自动处理。

我已经创建了一个自定义目标标签来表示客户的响应能力。

对于二元分类,它将简单地根据完成的报价百分比对客户进行分类。如果报价完成百分比> 50 %,则客户属于“响应型”客户。否则,它属于“无响应”类。

稍后,我将问题扩展到多类分类。为此,我创建了 3 级、4 级和 5 级标签,将完成的报价百分比分配给特定的类别,并为每个类别分配适当的标签。

对于 5 类问题,标签编码如下:

编码= {

‘响应’:4,
‘非常响应’:0,
‘中等响应’:3,
‘非常响应’:2,
‘无响应’:1

模型评估策略

1。超参数固定值的模型评估(基础模型)

我在所有分类问题(class_2,class_3,class_4,class_5)上使用以下固定超参数评估 CatBoost 分类器

迭代次数= 2000

loss _ function =[’ multi class ']

早停轮数= 50

eval_metric = ‘Accuracy’

其余参数值默认由 CatBoost 分类器提供。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

使用固定超参数的基本模型评估

2。使用 GridSearch 找到的超参数进行模型评估(调整模型)

在这一轮实验中,我编写了一个定制的 GridSearch 函数,它为每个给定的超参数范围找到最佳值,并返回训练数据上平均精度最佳的模型超参数。

对于 CatBoost Multiclassifier,有许多超参数需要优化。可在此处找到详细列表:

我只选择了以下具有指定范围的超参数(通过在 CatBoost 网站和 Kaggle 上的一些研究找到),以找到具有最佳性能的模型。

- iterations = [1000,3000]
- loss_function =  ['Logloss','MultiClass','MultiClassOneVsAll']
- depth = [4,6,8]      
- early_stopping_rounds = [10, 20, 50]

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

使用 GridSearch 的最佳发现超参数模型评估

8.结论+反思

  • 我评估了四个多类分类模型并记录了结果。似乎训练精度是模型性能的可靠指标,而不是测试精度。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

综合两种评估

  • 这表明基本模型实际上比通过 GridSearch 找到参数的模型表现得更好。这可能是因为范围选择没有优化。在未来的工作中,使用 RadomizedGridSearch 评估模型可能会很有趣。
  • 向 GridSearch 提供太多的参数会导致搜索非常慢(一个模型需要 7 个多小时),因此我缩小了参数范围,然后平均花费 20 分钟来搜索最佳参数。
  • 最初,我面临一些清理事务和确定如何使用事务数据进行数据建模的挑战。关键的洞见是识别出同一时间线与不同事件相关。这让我能够绘制一些伟大的客户旅程可视化和随后的定制功能创建。
  • 总的来说,我觉得参与这个项目很令人兴奋。我学到了很多关于数据分析的东西,特别是使用散景的数据可视化。
  • 使用 CatBoost 创建一个模型需要一些初步的尝试和错误。尽管我没有改变很多默认参数,但结果非常好。部分原因是因为我在训练集中包括了像“查看的报价数量”这样的功能,这是报价完成率的一个很好的指标,基于此,我对目标类进行了编码。

未来细化

  • 我建议尝试自定义分类特征来训练模型。
  • 此外,从数据集中移除一些自定义要素并评估模型也会很有趣。
  • 关于特征工程,可以开发关于顾客在查看报价之前已经花费多少的特征。

非常感谢您阅读这篇文章。如果你对该项目的更多细节感兴趣,请点击查看项目资源库

星巴克优惠数据集——uda city 顶点

原文:https://towardsdatascience.com/starbucks-offer-dataset-udacity-capstone-7b562843ff47?source=collection_archive---------15-----------------------

实践教程

对“浪费要约”的调查

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

卡尔·弗雷德里克森Unsplash 上拍摄

介绍

Starbucks Offer Dataset 是学生可以从中选择的数据集之一,以完成他们的 Udacity 数据科学纳米学位的顶点项目。该数据集包含模拟数据,模拟顾客收到星巴克报价后的行为。这些数据是通过星巴克奖励移动应用程序收集的,优惠每隔几天就会发送给移动应用程序的用户。

数据文件包含 3 个不同的 JSON 文件。

*File descriptions provided by Udacity*portfolio.json — containing offer ids and meta data about each offer (duration, type, etc.)profile.json — demographic data for each customertranscript.json — records for transactions, offers received, offers viewed, and offers completed

有 3 种不同类型的优惠:买一送一(BOGO),折扣,和信息意味着纯粹的广告。然而,对于每种类型的优惠,优惠期限、困难或促销渠道可能会有所不同。该数据集包含大约 300,000+个模拟事务。

这个项目的目标不是由 Udacity 定义的。因此,它是开放式的。尽管如此,从为星巴克提供商业价值的角度来看,问题总是要么:我们如何增加销售额,要么我们如何省钱。如何省钱的问题不是不花钱,而是不把钱花在无效的事情上。

从这两个角度来看,都有很多值得探索的东西。Udacity 给出的一个警告引起了我的注意。它警告我们,一些优惠在用户不知情的情况下被使用,因为用户不会加入这些优惠;报价已经给出。因此,如果一些用户不管有没有优惠都会在星巴克消费,我们还不如保存这些优惠。

我觉得这是个有趣的问题。我决定对此进行调查。我想看看我是否能找出这些用户是谁,我们是否能避免或尽量减少这种情况的发生。在下面的文章中,我将介绍我是如何研究这个问题的。我将遵循 CRISP-DM 流程。如果你不熟悉这个概念。这是我写给你的一篇文章。

[## 数据科学在线课程没有教给你的两件重要事情

如果你的数据科学在线课程大纲看起来像…

towardsdatascience.com](/2-crucial-things-that-data-science-online-courses-didnt-teach-you-2da0ae3267bd)

业务理解和数据理解

我们先来看看数据。从数据集来看,很明显,我们需要组合所有三个数据集,以便执行任何分析。此外,数据集需要大量清理,主要是因为我们有许多分类变量。

下面是我希望在分析结束时解决的五个业务问题。前三个问题是为了对数据集有一个全面的了解。最后两个问题直接解决了我想调查的关键业务问题。

  • Q1:哪个是最受欢迎的提议?
  • Q2:不同的人群对报价有不同的反应吗?
  • 问题 3:人们通常会查看并使用优惠吗?还是他们在没有注意到的情况下使用了报价?
  • Q4:如果存在这样一个群体,那么哪一类人更有可能在没有查看报价的情况下使用报价或进行购买?
  • Q5:如果有,哪种类型的优惠更有可能在不被查看的情况下被使用?

在我摆弄了一下数据之后,我还决定在这个分析中只关注 BOGO 和折扣优惠,主要有两个原因。一是因为我相信 BOGO 和折扣优惠与信息性优惠/广告有着不同的商业逻辑。对于 BOGO 和折扣优惠,我们希望找出不知情的人,这样我们就不会白花钱。对于这个广告,我们想确定哪一组人被鼓励花更多的钱。换句话说,一个逻辑是确定损失,而另一个是衡量增长。

另一个原因和第一个原因联系在一起,就是关于范围的问题。由于不同的业务逻辑,我想把这个分析的范围限制在只回答这个问题:谁是“浪费”我们的产品的用户,我们如何避免它。因此,我没有分析信息提供类型。

成功指标及其合理性

重复一遍,我想要解决的商业问题是调查用户在没有观看我们的产品的情况下使用它的现象。换句话说,优惠没有起到刺激消费的作用,因此被浪费了。因此,关键的成功标准是我是否能识别出这群用户以及这种行为背后的原因。此外,如果我可以建立一个机器学习模型来预测这种情况何时可能发生,这将是有帮助的。在这种情况下,该公司将处于一个更好的位置,不会浪费这个机会。

明确地说,关键的成功标准是我是否对上面列出的所有问题都有明确的答案。因为能够回答这些问题意味着我可以清楚地识别出有这种行为的用户群,并对原因进行一些教育猜测。

对于机器学习模型,我重点以交叉验证准确率和混淆矩阵作为评价。准确性分数很重要,因为我的模型的目的是帮助公司预测何时要约可能会被浪费。所以精度越高越好。

当然,当数据集高度不平衡时,准确度分数不会是实际准确度的良好指标,精确度分数、f1 分数或混淆矩阵会更好。然而,在这种情况下,不平衡的数据集不是一个大问题。两个虚拟模型,其中一个使用随机猜测的方法,另一个使用全部选择多数的方法,一个具有 51%的准确度分数,另一个具有 57%的准确度分数。这表明数据集不是高度不平衡的。

我选择混淆矩阵作为第二个评估矩阵,与交叉验证准确性一样重要。原因是与假阳性和假阴性相关的商业成本可能不同。因此,了解模型更容易出现哪种类型的错误将是有益的。有些人喜欢 f1 的分数。然而,我发现 f1 的分数有点难以理解。因此,我坚持使用混淆矩阵。为了更好地处理第一类和第二类错误,这里是我之前写的另一篇文章,有更多的细节。

[## 为什么一定要说 1 型错误和 2 型错误?

从模型评估到商业决策…

towardsdatascience.com](/programming-journal-4-why-do-we-have-to-talk-about-type-1-error-and-type-2-error-41b3ae68bb96)

数据准备

在数据准备阶段,我主要做了两件事。一个是合并 3 个数据集。另一个是将所有的分类变量转换成数字表示。

合并 3 个数据集的一个困难是抄本数据集中的’值’‘列包含报价 id 和美元金额。此外,该列是一个字典对象。下面是我如何使用’ offer_id '来分隔列,以便数据集可以与投资组合数据集相结合。

当把分类变量转换成数值变量时。有两个更复杂的列,一个是“*年”列,另一个是“通道”列。‘year’*列很棘手,因为数字表示的顺序很重要。举个例子,如果我用:0–2017,1–2018,2–2015,3–2016,4–2013。这违背了我们的直觉。然而,对于其他变量,如“性别”和“事件”,数字的顺序并不重要。因此,我为分类变量编写了一个不需要考虑顺序的函数。

*‘channel’*列比较棘手,因为每个单元格都是一个对象列表。有两种方法可以解决这个问题。一种方法是将每个通道转换成列索引,并用 1/0 表示该行是否使用了该通道。然而,我使用了另一种方法。我意识到有 4 种不同的频道组合。我想知道不同的组合对每个优惠有什么不同的影响。所以,我想把物品清单当做 1 个东西。我是这样处理的。

EDA 和结果:

Q1:哪个是最受欢迎的提议?

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

左边绝对数字,右边百分比|作者图片

回答:折扣优惠更受欢迎,因为它不仅在绝对值方面“报价完成”的数量略高,而且总体完成/接收率也更高(~7%)。然而,值得注意的是,BOGO 优惠有更大的机会被顾客看到。

Q2:不同的人群对报价有不同的反应吗?

在两个图表中,红色的“否”表示未完成(查看或收到),绿色的“是”表示“报价完成”。

对于 BOGO 的提议

对于折扣优惠

回答:对于这两种提议,男性完成的几率都要低得多。越是忠诚的客户,加入 5-6 年的人使用这两种优惠的机会也越低。比较这两种优惠,女性稍微更多地使用 BOGO,而男性更多地使用折扣。然而,仅仅从外观上看,这两个报价之间并没有太大/显著的区别。

问题 3:人们通常会查看并使用优惠吗?还是他们在没有注意到的情况下使用了报价?

答:在实验时间的前 5 天中,“要约已完成”的峰值略早于“要约已查看”。随着时间的推移,它们同步得更好,这表明大多数人有意识地使用了这个提议。随着时间的推移,“已完成报价”和“已查看报价”之间的差距也在缩小。

Q4:如果存在这样一个群体,那么哪一类人更有可能在没有查看报价的情况下使用报价或进行购买?

我挑选了客户 id,它的第一个要约事件是“offer received ”,随后是第二个事件“offer completed”。他们是跳过“已查看报价”的人。然后,我将他们的人口统计信息与其他人进行了比较。这是项目中最棘手的部分,因为我需要弄清楚如何提取对要约的第二个响应。我是这样做的。

以下是我的分析结果:

答:正如您所看到的,没有显著的差异,这令人失望。这表明,所有客户都有可能在不看我们的产品的情况下使用我们的产品。那么,这可能与我们设计产品的方式更有关系吗?我们来看下一个问题。

Q5:如果有,哪种类型的优惠更有可能在不被查看的情况下被使用?

如您所见,产品的设计的确与众不同。例如,蓝色部分,即报价以“1d7”结尾,明显大于正态分布(~17%)。以“2a4”结尾的报价也比正态分布高出 4–5%。以下是关于这些优惠的信息,按照它们在没有被注意到的情况下被使用的次数排序。

回答:我们看到促销渠道和持续时间起着重要的作用。从这个分析中我们可以得出以下结论。

  • 如果一份工作是通过网络和电子邮件推广的,那么它被发现的机会就大得多
  • 在不查看的情况下用于链接到优惠的持续时间。持续时间越长
  • 与 BOGO 相比,折扣优惠类型也有更大的机会不用看就能使用。

建模和评估

我想调查的主要问题是,谁浪费了这些提议,这个问题已经被之前的数据工程和 EDA 解决了。建立机器学习模型的目的是预测一项提议被浪费的可能性。如果机会很大,我们可以计算商业成本并重新考虑决定。因此,该模型可以帮助最小化“浪费要约”的情况。

对于模型选择,我正在决定是使用决策树还是逻辑回归。我将范围缩小到这两个,因为在这种情况下,拥有预测的类别概率也是有用的。我们可以知道我们对一个特定的预测有多有信心。此外,我们可以设定,如果只有 70%以上的机会,客户会浪费一个报价,我们将考虑撤回一个报价。对我来说,仅仅因为客户有 51%的机会浪费它,就撤销一个报价是没有意义的。

我最终选择了逻辑回归,因为它更稳健。决策树通常需要更多的调整,并且对不平衡数据集等问题更加敏感。我们的数据集与

1- ‘wasted offers’: 31723
0- ‘used offers’: 23499

建模前的一个重要步骤是获得正确的标签。在这种情况下,标签“浪费”意味着客户要么根本没有使用该产品,要么使用后没有查看。以下是我如何创建这个标签。

然后我丢弃所有其他事件,只保留*‘浪费的’*标签。我将这个数据集与 profile 和 portfolio 数据集合并,以获得我需要的特性。最终,数据框看起来像这样:

我使用 GridSearchCV 来调整逻辑回归模型中的*【C】参数。我使用默认的【L2】作为惩罚。*原因是我们在数据集中没有太多的特征。代码如下:

最佳模型实现了 71%的交叉验证准确性,75%的精确度分数。对于混淆矩阵,假阳性的数量(15%)多于假阴性的数量(14%),这意味着该模型更有可能在现实中不会被浪费的报价上出错。

为了改进模型,我对多数标签进行了下采样,并平衡了数据集。我使用下采样而不是上采样或 smote 等其他方法的原因是:1)即使在下采样后,我们也有足够的数据 2)根据我的理解,不平衡数据集不是由于有偏差的数据收集过程,而是由于可用样本较少。在这种情况下,使用 SMOTE 或上采样会导致数据集过拟合的问题。更多细节,下面是我深入探讨这个问题时的另一篇文章。

[## 从不平衡数据集到助推算法

不平衡数据集完整工具包

朝向数据科学](/from-imbalanced-dataset-to-boosting-algorithms-1-2-798cd6384ecc)

在平衡数据集后,最佳模型的交叉验证准确性增加到 74%,精确度分数仍为 75%。对于混淆矩阵,假阳性减少到 11%,假阴性减少到 15%。这意味着模型更有可能在现实中想要的报价上出错。通过调整更多的参数或尝试像 XGboost 这样的树模型,该模型有很大的潜力可以进一步改进。但是,由于个人时间和精力的限制,我就此打住了。

总结/概括

总之,我已经向您介绍了我如何处理数据来合并 3 个数据集,以便我可以进行数据分析。我谈到了我如何使用 EDA 来回答我在文章开始时提出的业务问题。在这个过程中,您可以看到我需要如何进一步处理我的数据以适合我的分析。我还强调了处理数据最困难的地方,以及我是如何处理这个问题的。

结果硕果累累。我成功地回答了我提出的所有商业问题。虽然,在调查之后,问这样一个问题似乎是错误的:谁是没有看我们的产品就使用了它的顾客?相反,问题应该是:为什么我们的报价没有被浏览就被使用了?原因是人口统计并不重要,但优惠的设计很重要。

最后,我用逻辑回归建立了一个机器学习模型。我解释了为什么选择模型,如何准备模型处理的数据以及模型的结果。我使用了 3 种不同的指标来衡量模型、交叉验证准确性、精确度分数和混淆矩阵。在这篇文章的最后,我想对商业和潜在的未来研究提出一些建议。

最后建议和未来研究

为了避免或改善不经查看就使用报价的情况,我建议如下:

  • 通过至少 3 个渠道推广产品,增加曝光率
  • 排除持续 10 天的报价,最大值。7 天。如果一个报价真的很难,20 级,客户就不太可能为之努力。与此同时,那些实现这一目标的人很可能会实现这一数额的支出,而不管报价如何。

我的另一个建议是,我相信折扣优惠有很大的潜力。在那些浏览过报价的人中,完成率为 78%。因此,如果公司能够提高折扣优惠的收视率,就有很大的机会刺激更多的支出。

对于以后的学习,还有很多可以做的。最显而易见的两件事是执行一项分析,合并来自信息提供的数据,并改进我当前模型的性能。观察顾客对信息提供的反应以及广告或信息提供是否也有助于 BOGO 和折扣的表现将是有趣的。将我的模型准确率提高到 85%以上会很有帮助。

我的全额回购可以在这里进入

星巴克促销活动:你会花钱吗?

原文:https://towardsdatascience.com/starbucks-promotional-campaigns-will-you-spend-your-money-9e8e965ab3d?source=collection_archive---------79-----------------------

使用 Python 和 ensemble 方法深入挖掘星巴克顾客

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

埃里克·麦克林在 Unsplash 上的照片

每当星巴克向你提供买一送一的促销活动时,你会感到兴奋吗?然而,你被这个优惠吸引到最近的星巴克店消费了吗?

简介

所使用的数据集包含来自星巴克的模拟数据,这些数据模拟了顾客在他们的 rewards 移动应用上的行为。星巴克每隔几天就会发出一次优惠,可以是饮料的广告,也可以是实际的优惠,如折扣或 BOGO(买一送一)。然而,并不是每个用户都能得到相同的优惠,而且在优惠到期之前,每个优惠都有一个有效期。

通过将年龄和性别等人口统计数据与交易和报价数据相结合,我们希望实现两个目标:

1。报价视图和已完成的预测模型

想象自己是一名收入一般的年轻女性,当你查看手机时,你看到一则广告:星巴克的 BOGO 促销活动将在 3 天后到期。你会使用促销吗?

或者想象一下如果你是一个富裕忙碌的中年男性。你会有时间去看星巴克的广告吗?或者你会直接在最近的星巴克店里使用 BOGO 促销活动?

该模型旨在预测特定人群中的特定客户是否会查看或/和完成星巴克发送的报价。

2。平均支出预测模型

相对于平均交易,星巴克给你的优惠有多有效?如果您收到并查看了星巴克的某些优惠,您会在星巴克消费多少金额?该模型旨在了解会员在看到优惠后直到有效期到期平均会花多少钱。

第一部分报价查看&完成预测模型

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

由作者拍摄

基于上面的相关图,推广变量(类型、奖励、难度)而不是人口统计属性影响更多的人观看广告。像 BOGO 这样的提议似乎很有吸引力。超过 70%的优惠被会员查看。与只有 57.9%成功率的其他类型的活动相比,这是一个非常显著的数字。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

由作者拍摄

然而,故事是不同的其他类型的运动,如信息运动,将通知你,如果有新类型的饮料。只有 55%的会员观看了广告。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

由作者拍摄

与报价最相关的人口统计属性是年龄组。如下图所示,年轻成人年龄组(17-25 岁)中有 41.6%的会员甚至不屑于看到报价,而其他年龄组的成功率为 63.1%。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

由作者拍摄

这是为什么呢?似乎年轻的成年人群体对 BOGO 的促销活动反应良好。68.2%的人看过 BOGO 的竞选活动,只有 52%的人看过其他类型的竞选活动。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

由作者拍摄

现在,让我们继续讨论报价完成与其他变量的关系。请注意,当会员在促销有效期到期前超过最低消费时,优惠即被归类为已完成。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

由作者拍摄

发现的一个有趣的注意事项是,2018 年加入的成员(数据集的最新成员)的失败率为 71.5%。它比其他会员多了将近 20%!

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

由作者拍摄

但是优惠的类型呢?虽然 BOGO 活动是最成功的报价,但折扣活动对报价完成率的影响更大。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

由作者拍摄

性别在这里被证明是至关重要的。与女性相比,男性未完成工作的比例高出 14%。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

由作者拍摄

我们知道,与女性相比,男性不太可能完成报价。现在,什么样的男人会完成一个提议,什么样的提议足够吸引他们去完成?通过结合上面的另一个见解,我们可以看到折扣非常受欢迎,在 2018 年之前成为会员的男性中有 59%完成了折扣。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

由作者拍摄

让我们开始建模。由于有两个分类,即已查看和已完成的报价,因此使用 MultiOutputClassifier,这意味着将有四种不同类型的输出,即未查看和未完成报价的客户(0,0),未查看和完成报价的客户(0,1),已查看和未完成报价的客户(1,0),以及已查看和完成报价的客户(1,1)。两个集成学习模型,梯度提升和随机森林与网格搜索一起使用。

pipeline = Pipeline([
    ('clf', MultiOutputClassifier(GradientBoostingClassifier())) 
    ])parameters = [
    {
    "clf": [MultiOutputClassifier(GradientBoostingClassifier())],
    'clf__estimator__learning_rate':[0.5, 0.25],
    'clf__estimator__n_estimators':[100, 200],
    },
    {
    "clf": [MultiOutputClassifier(RandomForestClassifier())],
    'clf__estimator__n_estimators': [100,200]
    }]grid = GridSearchCV(pipeline, param_grid = parameters, cv=10, return_train_score=False)grid.fit(X_train, y_train)

在训练数据集中以 54%的最佳平均测试分数返回的最佳模型是具有学习率 0.25 和 n_estimators 100 的超参数的梯度增强。

为什么渐变提升比随机森林表现更好?对于不平衡数据集,如用于此模型的训练数据集(只有 8%的标签是未查看和完成报价的客户),梯度提升的性能优于随机森林。Boosting 一步一步地关注困难的例子,这些例子通过加强正类的影响给出了处理不平衡数据集的好策略。

让我们看看模型如何执行测试数据集。

y_pred = grid.predict(X_test)label = ['Offer Viewed', 'Offer Completed']report = classification_report(y_test, y_pred, output_dict=True, target_names=label)confusion_matrix_viewed = multilabel_confusion_matrix(y_test, y_pred)[0]
accuracy_viewed = round(sum(confusion_matrix_viewed.diagonal())*100/confusion_matrix_viewed.sum(), 2)
recall_viewed = round(report['Offer Viewed']['recall']*100,2)
precision_viewed = round(report['Offer Viewed']['precision']*100,2)
confusion_matrix_completed = multilabel_confusion_matrix(y_test, y_pred)[1]
accuracy_completed = round(sum(confusion_matrix_completed.diagonal())*100/confusion_matrix_completed.sum(), 2)
recall_completed = round(report['Offer Completed']['recall']*100,2)
precision_completed = round(report['Offer Completed']['precision']*100,2)print('The overall accuracy of the model on both class in the test dataset is {}%. Accuracy, recall and precision for offer viewed are {}%, {}% and {}%, \
while accuracy, recall and precision for offer completed are {}%, {}% and {}%.'.format(round(grid.score(X_test, y_test)*100,2),\                                                                              accuracy_viewed,recall_viewed,precision_viewed,\                                                                                   accuracy_completed,recall_completed,precision_completed))

该模型在测试数据集中对两个类的总体准确率为 53.85%。已查看要约的准确率、召回率和准确率分别为 71.03%、80.39%和 75.13%,已完成要约的准确率、召回率和准确率分别为 72.44%、70.27%和 66.84%。

第二部分。平均支出预测模型

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

由作者拍摄

人口统计组属性,如收入、性别和年龄组,在会员在优惠有效期内查看优惠后,主导与会员平均消费的相关性。

被归类为高收入成员的成员通常花费大约 30 美元,中等收入成员通常花费 20 美元,低收入成员通常花费大约 5-10 美元。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

由作者拍摄

男性和女性在看到报价后的消费行为是不同的。女性通常花费 25-30 美元,而男性通常只花费 10 美元以下。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

由作者拍摄

最有趣的是老年组(60 岁以上)和其他年龄组之间的比较。老年人群花费最多,大约 30 美元,而其他年龄组大约 10 美元。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

由作者拍摄

让我们开始建模。梯度推进和随机森林与网格一起用于搜索最佳模型和超参数。

pipeline = Pipeline([
    ('clr', GradientBoostingRegressor()) 
    ])parameters = [
    {
    "clr": [GradientBoostingRegressor()],
    'clr__learning_rate':[0.5, 0.25, 0.1],
    'clr__n_estimators':[100, 200,300],
    'clr__max_depth':[10,20,50]
    },
    {
    "clr": [RandomForestRegressor()],
    'clr__n_estimators': [100,200,300],
    'clr__max_depth':[10,20,50],
    'clr__min_samples_split':[2, 5, 10]
    }]grid_amount = GridSearchCV(pipeline, param_grid = parameters, cv=10, return_train_score=False)grid_amount.fit(X_train, y_train.values.ravel())y_pred_train = grid_amount.predict(X_train)
print(mean_absolute_error(y_train, y_pred_train))
print(mean_squared_error(y_train, y_pred_train))

运行网格搜索后的最佳模型是随机森林,其超参数估计数为 300,最大深度为 10,最小样本分裂为 10。训练数据集上的平均绝对误差和均方误差分别为 5.52 和 186.80。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

由作者拍摄

对于这种回归问题,随机森林的表现优于梯度增强的原因是因为数据中存在异常值(见上图)。离群值可能对 boosting 不利,因为 boosting 将每棵树建立在先前树的残差/误差上。异常值将比非异常值具有大得多的残差,因此梯度增强将在这些点上集中不成比例的注意力。

让我们看看它在测试数据集中的表现。

y_pred = grid_amount.predict(X_test)
print(mean_absolute_error(y_test, y_pred))
print(mean_squared_error(y_test, y_pred))

在测试数据集上,平均绝对误差和均方误差分别为 6.33 和 279.52。

与数据集中从 0 到 600 的平均支出范围值相比,6.33 的平均绝对误差听起来令人吃惊,但是我们应该考虑到数据集的平均值只有 15 左右。

第三部。结论&改进

  1. 优惠类型等促销属性会影响会员查看他们收到的优惠的行为。70%的会员会查看像 BOGO 这样的优惠类型。
  2. 在完成报价的过程中,人口属性起着重要作用。与女性相比,男性未完成工作的比例高出 14%。
  3. 对于提供已查看和已完成的模型,梯度增强的性能优于随机森林模型,因为对于不平衡数据集,它的性能优于随机森林。为了改进,欠采样或过采样不平衡类可以解决这个问题。梯度增强模型在测试数据集中的两个类上的总体准确度是 53.85%。已查看要约的准确率、召回率和准确率分别为 71.03%、80.39%和 75.13%,已完成要约的准确率、召回率和准确率分别为 72.44%、70.27%和 66.84%。
  4. 在报价有效期内,不同的人口统计组在他们观看某些报价后,相对于他们花费的平均金钱表现不同。男性通常只花 10 美元以下,而女性通常花 25-30 美元左右。
  5. 对于平均支出模型,随机森林比梯度增强模型表现更好,因为数据集中存在离群值。为了改进,处理异常值可能会解决这个问题。测试数据集中的平均绝对误差和均方误差分别为 6.33 和 279.52。

参考文献

完全归功于 Udacity 和 Starbucks 提供的数据集。你可以在这里看到完整的代码:【https://github.com/dhaneswaramandrasa/starbucks】T2。

  1. 【http://ecmlpkdd2017.ijs.si/papers/paperID241.pdf
  2. https://medium . com/@ aravanshad/gradient-boosting-vs-random-forest-CFA 3 fa 8 f 0d 80
  3. https://stats . stack exchange . com/questions/140215/why-boosting-method-is-sensitive-to-Outliers #:~:text = Outliers % 20 can % 20 be % 20 bad % 20 for,its % 20 attention % 20 that % 20 points。

Python 中的星图

原文:https://towardsdatascience.com/stars-charts-in-python-9c20d02fb6c0?source=collection_archive---------35-----------------------

使用 Diamonds 和 Matplotlib 创建星图的教程

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

戴夫·赫林在 Unsplash 上拍摄的照片

钻石是数据科学家最好的朋友。更具体地说,在 Kaggle 上发现的钻石数据集。在本文中,我将通过一个简单的工作流程来创建一个星图(又名蜘蛛图或雷达图)。本教程改编自 Alex 在 Python Charts 的精彩工作流程。本文中的所有代码和所需的数据集都可以在 GitHub 的中找到。

钻石是数据科学家最好的朋友

首先,您需要几个库。我正在运行 Python 3。我使用 Jupyter 笔记本、pandas、matplotlib 和 numpy 创建了这个工作流。如果您的系统中没有这些软件包,可以通过 pip 或 conda 安装它们。

pip install jupyterlab
pip install pandas
pip install matplotlib 
pip install numpy

数据集可以从 Kaggle 下载,大小应该在 3.2 MB 左右。我已经在 Github 上包含了数据集的副本。我在数据文件夹里有数据集。用熊猫加载数据集,删除额外的索引列,我们就可以开始了!

df = pd.read_csv("data/diamonds.csv")
df.drop("Unnamed: 0", axis=1, inplace=True)

3 C 的水平

钻石的 4 C 标准是切割、颜色、净度和克拉。切割、颜色和净度被定义为钻石行业中使用的分类变量。克拉是代表宝石重量的数字。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

照片由张浩Unsplash 上拍摄

为了创建星形图,我们需要用数字来表示钻石行业术语。为此,我们需要收集数据集中的级别信息。Cut 由五个级别组成,其中理想为最高级别【4】,一般为最低级别【0】。在颜色的七个等级中, D 为最高等级【6】,而 J 为最低等级【0】。最后,净度由八个级别组成,其中 **IF、**表示内部无瑕疵为最高级别【7】,而 I1 、内含物级别 1 为最低级别【0】。

显示切割和抛光数据

在我们的数据集中,我们剔除了 3 个偏离下游色谱柱刻度的异常值。

## Cut diamonds that skew carat range
indicies_to_remove = [27415, 27630, 27130]
df = df.drop(indicies_to_remove)

接下来,我们在数据帧中创建新的列来存放通过将字典映射到 C 的列而创建的排名。下面是一个映射示例。

cut={'Ideal':4,'Premium':3,'Very Good':2,'Good': 1,'Fair':0}
df['Cut'] = df['cut'].map(cut) #Note: 'Cut' is a different column

最后,我们需要缩放我们将在星形图中使用的列,以公平地表示数据。

## Convert all rankings and contiguous data to scale between 0-100
factors = ['Cut', 'Color', "Clarity", "carat", "price"]new_max = 100
new_min = 0
new_range = new_max - new_min## Create Scaled Columns
for factor in factors:
    max_val = df[factor].max()
    min_val = df[factor].min()
    val_range = max_val - min_val
    df[factor + '_Adj'] = df[factor].apply(lambda x: (((x - min_val) * new_range) / val_range) + new_min)

然后,我们将缩放后的列划分为子集,用于下游绘图。请注意,我们正在创建一个新的数据框架(df2 ),其中仅包含我们打算在星形图中使用的列。

## Subset scaled columns 
df2 = df[['Cut_Adj', "Color_Adj", "Clarity_Adj", "carat_Adj", "price_Adj"]]
df2.columns = ['Cut', "Color", "Clarity", "Carat", "Price"]

演出的明星

要创建星形图表,我们必须指定要使用的列,并使用 numpy 创建圆形绘图对象。

labels = ['Cut', "Color", "Clarity", "Carat", "Price"]
points = len(labels)angles = np.linspace(0, 2 * np.pi, points, endpoint=False).tolist()
angles += angles[:1]

然后,我们创建一个助手函数,仅通过索引号绘制一个菱形。

def add_to_star(diamond, color, label=None):
    values = df2.loc[diamond].tolist()
    values += values[:1]
    if label != None:
        ax.plot(angles, values, color=color, linewidth=1, label=label)
    else:
        ax.plot(angles, values, color=color, linewidth=1, label=diamond)
    ax.fill(angles, values, color=color, alpha=0.25)

现在魔法开始了!我们可以开始用我们想要的钻石填充我们的星图。最贵的和两个最便宜的怎么样:

## Create plot object   
fig, ax = plt.subplots(figsize=(6, 6), subplot_kw=dict(polar=True))## Plot a new diamond with the add_to_star function
add_to_star(27749, '#1aaf6c', "Most Expensive Diamond")
add_to_star(0, '#429bf4', "Least Expensive A")
add_to_star(1, '#d42cea', "Least Expensive B")

这个数量足以创建一个星图,但是,没有 x 标签,没有方向,也没有自定义风格。让我们改变这一切!

## Fix axis to star from top
ax.set_theta_offset(np.pi / 2)
ax.set_theta_direction(-1)## Edit x axis labels
for label, angle in zip(ax.get_xticklabels(), angles):
    if angle in (0, np.pi):
        label.set_horizontalalignment('center')
    elif 0 < angle < np.pi:
        label.set_horizontalalignment('left')
    else:
        label.set_horizontalalignment('right')## Customize your graphic# Change the location of the gridlines or remove them
ax.set_rgrids([20, 40, 60 ,80])
#ax.set_rgrids([]) # This removes grid lines# Change the color of the ticks
ax.tick_params(colors='#222222')
# Make the y-axis labels larger, smaller, or remove by setting fontsize
ax.tick_params(axis='y', labelsize=0)
# Make the x-axis labels larger or smaller.
ax.tick_params(axis='x', labelsize=13)# Change the color of the circular gridlines.
ax.grid(color='#AAAAAA')
# Change the color of the outer circle
ax.spines['polar'].set_color('#222222')
# Change the circle background color
ax.set_facecolor('#FAFAFA')# Add title and legend
ax.set_title('Comparing Diamonds Across Dimensions', y=1.08)
ax.legend(loc='upper right', bbox_to_anchor=(1.3, 1.1))# Draw axis lines for each angle and label.
ax.set_thetagrids(np.degrees(angles), labels)

那么产量是多少呢?

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

最贵和最便宜的两颗钻石的星图。Carets 似乎是价格的一大驱动因素。

最物有所值的珠宝

4 C 系列中价格最低、评级最高的钻石是什么?要找出答案,我们必须得到 4 个 C 的总价值,然后除以原始(未缩放)价格。这个部分对包含所有原始列的原始数据帧进行操作。为了计算总数,我们对四个缩放的列求和。

df['Total'] = df['Cut_Adj'] + df['Color_Adj'] + df['Clarity_Adj'] + df['carat_Adj']## Divide Value total by Price
df['4C_by_Price'] = df['Total']/df['price']
df = df.sort_values(by="4C_by_Price", ascending=False)

对我们来说最闪亮的钻石是#31597,最不闪亮的钻石是#26320。这些钻石在星图上如何比较?下面我们来探讨一下:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

一个是交易中的钻石,另一个是一大块碳。

结论:

感谢您使用 matplotlib 探索星形图表格式中的一些钻石特征。如果你有任何问题,请在下面或者完整代码的位置 GitHub 库发表。我的名字是科迪·格利克曼,我可以在 LinkedIn **上找到。**一定要看看其他一些关于有趣的数据科学项目的文章!

[## 使用 Python 创建照片镶嵌

一步一步的教程,让你自己的美丽的图像

towardsdatascience.com](/creating-photo-mosaics-using-python-49100e87efc) [## 刮胡子,还是不刮胡子,这是个问题

使用深度学习对有胡须和无胡须的照片进行年龄分类

towardsdatascience.com](/to-beard-or-not-to-beard-that-is-the-question-b46864d7e003) [## 使用 Dash 和 SQL 快速浏览圣诞歌曲

使用 SQL 数据库创建 Dash 仪表板的简单项目

towardsdatascience.com](/dashing-through-christmas-songs-using-dash-and-sql-34ef2eb4d0cb)

通过基本的统计数据开始看清事物

原文:https://towardsdatascience.com/start-to-see-things-clearly-with-basic-statistics-4acb2d4c7dc4?source=collection_archive---------57-----------------------

赤裸裸的统计,统计类和现实生活中的情况之间的桥梁,在一个有趣和深刻的方式

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

马尔科姆·莱特曼在 Unsplash 拍摄的照片

我其实不记得裸体统计是怎么来找我的。大概是这几个月看的一篇关于统计学的文章推荐的吧。

我决定给这本书一个机会,在一开始,我读了以下内容:

我通常知道我不知道的事情——查理斯·惠兰

很有趣,对吧?幸运的是,我提前意识到这本书很有可能值得一读。几个星期后,带着很多注解,我来了。这真的值得吗?

如果您对以下任何一项感兴趣:

  1. 一些真实的社会经济问题是如何被研究的,最重要的是,是什么使得这些问题如此难以解决,以及它们潜在的缺陷;
  2. 一般的分析情境与通常探究的情境有何不同。

…或者,当然,两者兼而有之,你打赌这是值得的。

作为一本统计学书籍,它的基础当然是统计学。因此,重要的是要强调,你可能需要重温一些你在学校或大学里学过的公式和概念,以便完全了解结果背后的分析是如何完成的。如果你从未学习过(或者什么都不记得了),这绝对是一个很好的途径,可以用来指导你的基础统计学学习。

然而,这不是一个关于统计公式或者数学推理的帖子。讲的是分析数据时的视角。

为了让你不被蒙在鼓里,我列出了一些你在阅读时将要面对的概念:

  • 平均值、中值、标准差、方差、异常值和四分位数
  • 相互关系
  • 可能性
  • 中心极限定理
  • 推理
  • 回归分析

好的,上面提到的所有这些和透视有什么关系?

“健康的用户偏好”

这是典型的因果关系误解和看问题时未观察到的差异的混合。

正如书中所写,“定期服用维生素的人很可能是健康的——因为他们就是那种定期服用维生素的人!”。你已经明白了吗?

维生素对人们健康的影响当然非常重要,但是,还有什么呢?让我们进一步探索…让我们分别看看每一部分,坚持两者的相同故事:

  1. 因果关系——关联误解:这是众所周知的情况。简而言之,两件事密切相关的事实并不一定意味着一个变量的变化导致了另一个的变化。正如书中所解释的那样,平均来说,一个家庭拥有的电视越多,学生在 SAT 考试中取得的成绩就越好。因此,电视的数量与良好的测试性能有一定的正相关关系。然而,购买新电视并不会使某个学生在 SAT 考试中表现得更好。看出区别了吗?
  2. 未观察到的差异:那么,上面有什么未观察到的呢?事实上,一个家庭中电视机的数量与家庭的富裕程度密切相关。认为参加额外数学课或有良好互联网接入的学生比那些不参加的学生更容易在考试中表现更好,这不是更合乎逻辑吗?

有时候,在分析情况时,我们倾向于对观察到的结果给自己具体的解释,而简单地忽略其他一切。大多数时候,这是无意中发生的(根据具体情况,这不是或者不应该是一个可以接受的解释)。

具有讽刺意味的是,查尔斯在书中走得更远,在第 7 章探索“紫色睡衣”的例子。

有很多我们日常生活中的例子,这里的要点是将这种认知扩展到我们日常面对的最可能的情况。起始问题是:为什么会这样 ?通常,我们已经在考虑一些见解来解释为什么会发生一些事情。而且,通常,一旦我们看到一个合理的方法来解释它,我们就不再试图更深入地理解这个问题。这不仅是关于服用维生素,也是关于其他一切。

其他条件不变

这是一个来自拉丁语的表达,意思是“其他条件相同”。

所有基于假设检验的例子都依赖于进行“受控实验,其中感兴趣的变量是实验组和对照组之间唯一不同的东西。“让我们再一次用一本书的实际例子。

在第一章中,查尔斯提出:“*吸烟会致癌吗?”。*你会怎么说?是的,对吗?我也是。然而,正如进一步探讨的那样,“回答这个问题的过程并不像人们想象的那么简单”。为什么?

这是因为“吸烟者和不吸烟者除了他们的吸烟行为之外,很可能在其他方面有所不同。比如?吸烟者很可能会有其他导致以后患癌症的习惯,如锻炼少、不良饮食习惯和酗酒。因此,当然,当你感兴趣的结果是癌症的原因时,吸烟是一个需要分析的重要因素,但是你不应该试图仅仅根据吸烟和不吸烟的习惯来解释癌症的原因。

现在没有办法考虑数据,也不要考虑新冠肺炎。当然,很明显,研究一种新的流行病的演变,同时做出重要的决定,对于世界各地的当局来说是一项非常困难的任务。但是,你有没有试着想一想为什么?

其中一个原因正是我们在这里探讨的。不仅国家本身,而且国家内部的具体区域在几个方面显示出彼此之间非常不同的现实。这就是为什么你可能在一些新闻媒体上听到有人说社会健康政策的应用应该考虑到每个地区的现实。每个地区都将呈现出特定的感染率、死亡率、重症治疗单位(ITUs)占用率、人群隔离率、人口规模、人口分布等诸多差异。出于这个原因,当局的决定不应该是适用于整个国家的一刀切的决定,因为不存在其他条件不变的现实*。*

这些只是这本神奇的书提供的一些例子和思考。我向你保证你会被激怒的。我不想给你更多的剧透,我真的希望这足以抓住你的好奇心。

正如书中提到的那样,“统计就像一把大口径武器:正确使用时很有帮助,但在错误的人手里可能是灾难性的”,而每个统计分析“只是需要良好判断的武器库中的一件武器”。尝试不同的视角,寻求全局,永远不要忘记自己的判断。

[1]: C. Wheelan,《赤裸裸的统计:从数据中剥离恐惧》(2013),W. W. Norton & Company。

开始在您现有的数据科学项目中使用 Git

原文:https://towardsdatascience.com/start-using-git-in-your-existing-data-science-project-27118c92f86e?source=collection_archive---------54-----------------------

现在开始使用 Git 还不算太晚

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

照片由 Yancy MinUnsplash 上拍摄

在数据科学中,你通常不是独自工作。使用 git 将有助于您与团队协作。即使你的项目中已经有了几样东西,现在开始使用 Git 还不算太晚。本文将指导您如何从现有的数据科学项目中启动 git 存储库。

我们开始吧!

第一步。准备 Git 账户/软件

  • 如果您还没有 git 帐户,请在线创建。请随意挑选你最喜欢的。我推荐 GitHub 或者 Gitlab
  • git-scm 安装到您的机器上。

第二步。创建存储库

拥有 Git 帐户后,创建一个新的空白项目存储库,并根据自己的喜好命名(与您的数据科学项目相匹配)。项目为空非常重要。不要创建任何文件或使用 Git 提供程序的任何模板。

然后,复制远程存储库 URL。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

git lab 资源库(左)和 Github 资源库(右)中的远程 URL 位置(图由作者提供)

第三步。在您的项目目录中启动 Git

在这一步中,我们将在您的工作目录中启动 Git。在窗口操作中,可以从右键菜单中打开 Git Bash 开始。在 Mac 中,您可以使用终端菜单。或者,您也可以使用 VS-Code 中的内置控制台。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

在 Window 操作系统上打开 Git Bash(图由作者提供)

然后,我们将使用git init命令启动本地存储库。接下来通过git add .命令将文件添加到本地存储库中。然后,我们使用git commit命令提交存储库中的文件变更。

**$ git init
$ git add .
$ git commit -m 'First commit'**

然后,我们需要使用步骤 2 中的git remote add ...命令,使用远程存储库 URL 将这个本地存储库添加到远程存储库中。通过将我们提交的更改推送到远程存储库,设置并确认一个带有git remote -v的新远程 URL。

**$ git remote add origin <**remote repository URL from step 2**>
$ git remote -v
$ git push origin master**

差不多就是这样!简单对吗?

结论

这篇短文介绍了如何以一种简单的方式在现有项目中启动 Git。如果您有任何问题、意见或建议,请随时给我留言。

安全健康**!**

感谢您的阅读。👋😄

开始使用 Linux 命令快速分析结构化数据,而不是熊猫

原文:https://towardsdatascience.com/start-using-linux-commands-to-quick-analyze-structured-data-not-pandas-f63065842269?source=collection_archive---------29-----------------------

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

照片由弗拉季斯拉夫Unsplash 上拍摄

有时我们需要快速分析或验证我们的结构化数据。一般来说,人们倾向于使用熊猫,因为它看起来简单而且视觉效果好。熊猫的问题是,如果你有大量数据,它可能会超级慢。

我们还有另一个选择,那就是 Linux 命令。Linux 命令运行速度非常快(即使是在海量数据上),你甚至不需要 IDE/笔记本来运行它。你可以在你的终端上执行它们。

我准备用本教程中著名的 泰坦尼克 数据作为例子。此外,为了更好地显示,我将在 Jupyter 笔记本中编写这些 Linux 命令(仅针对本教程)。

我们开始吧

我们在某个位置有一个名为titanic.csv的 CSV 文件。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

行数

我们先检查一下行数。我们可以使用 WC 命令来完成。

wc -<option> <file>

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

WC 代表字数。它可以读取一个文件的行数(-l)、字数(-w)和字符数。

先睹为快

通过做我们可以轻松地瞥一眼数据。我们可以检查列名和样本值。这和我们在熊猫身上做的一样。

head <file>

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

如果你想看到一个具体的行数,然后做

head -n <num_lines> <file>

同样,您可以看到数据的tail,它显示了数据的最后一部分。

tail -n <num_lines> <file>

逐列分析

列在结构化数据中很重要,您可以从数据中剪切/提取特定的列并对其进行分析。

我们可以使用 CUT 命令来提取特定的列。

cut -d'<delim>' -f<col_num> <file>

在这里,我删除了第 5 栏和第 6 栏(性别和年龄),而忽略了这两栏。您还可以提供列范围。例如,f1–3将提取第 1、2 和 3 列。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

在 Linux 中管道(|)是一个非常有用的操作符。我们可以使用管道在其他命令的输出上运行一个命令,就像我上面做的那样。首先,我提取了 2 列,然后做了标题。我们现在会经常看到管道的使用。

检查列的最小值-最大值

很多时候我们需要知道列的值域。这里我们可以使用排序命令来完成任务。

sort <option> <file>

让我们检查年龄列中的最大值。基本上是泰坦尼克号上年纪最大的人。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

我们看到它是 80。首先,我们剪切年龄列,然后以逆序(-nr)对该列进行排序,然后跳过它。

我们可以通过提供标志-n以数字顺序对列进行排序,通过提供标志-nr以相反的数字顺序对列进行排序。如果我们不提供-n标志,那么一列按字典顺序排序。

检查列中的唯一值

在这个数据中,我们有一个名为 cabin 的列,它告诉乘客所在的客舱 ID。让我们看看泰坦尼克号上总共有多少个船舱。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

我们看到总共有 149 个船舱。首先我剪切了 cabin 列,然后通过传递-u标志对该列进行排序,该标志只给出唯一的值。然后计算这些唯一值的数量。

在数据中搜索

很多时候,我们需要在数据中搜索文本。我们可以使用 GREP 命令来完成。我假设你已经熟悉了 regex (正则表达式)。

grep <option> "<regex>" <file>

假设我们想要查看乘客姓名以john开头的所有记录。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

grep命令搜索所有行中的文本john并打印匹配的行。参数-i在匹配时忽略大小写。我们在执行 grep 时提供了一个正则表达式。

检查列中的空值

让我们检查年龄列中空值的数量。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

首先,我们删除年龄列,然后使用^$ regex 清空空行。数一数这样的线。

检查范围内的值

让我们查一下有多少乘客年龄在 10 岁以下。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

有 62 名这样的乘客。基本上,如果你知道如何使用正则表达式,你可以在一个命令中做很多这样强大的事情。

最后一个例子:)

假设我们想要检查在车祸中幸存的男性人数。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

首先,我选择包含male单词的行。然后剪切第 2(幸存)列,然后重新标记其中值为 1 的行(其中 1 幸存,0 未幸存)。然后最后计算行数。所以我们有 161 个。

我们只需使用一个简单的 Linux 命令就可以完成几乎所有的基本分析,这个命令即使在处理大量数据时也运行得非常快。一旦你开始使用这些命令,你会发现你可以用它做更多的事情。

我希望这篇博客对你有所帮助。请让我知道你的想法。感谢阅读。

立即开始使用 Python 的 Unittest 模块

原文:https://towardsdatascience.com/start-using-pythons-unittest-module-today-17ba0537c5a0?source=collection_archive---------62-----------------------

Python 单元测试完整演练

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

乔恩·泰森在 Unsplash 上的照片

单元测试

单元测试是代码的基本运行。这是不是 QA。这种方式,你验证你已经写了质量代码,而不是在别人试图使用它的时候就会崩溃的东西。

为什么要测试?

最近,在一家初创公司,我需要为一位同事编写库代码,我给他库代码和一个单元测试脚本。

每次他抱怨的时候,单元测试为我节省了时间来检查他代码中的错误。因为我的工作了,这节省了很多时间,时间是你最宝贵的财富。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

照片由 insung yoonUnsplash 上拍摄

单元测试是开发的重要方面**。没有你的代码的第一次运行,你怎么知道它是否工作?由于单元测试通常很快很短,通过正确地管理单元测试,您可以看到您是否破坏了旧代码或其他人的代码!**

提供如何使用你的代码的例子将会很容易,因为你已经有一个了!

错误而常见的方式

让我们从展示错误的和常规的方法开始。这里有一个简单的类对象:

如你所见,这个类做的不多。它接受一个数字,并对给定的输入进行幂运算。现在,一个标准的开发人员会如何验证这些代码呢?

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

胡安·鲁米普努在 Unsplash 上拍摄的照片

这个方法好像不太对;以下是几个主要原因。

  • 这是不可持续的——只是分散在许多文件中的小测试,没有任何方法来跟踪甚至重用这些测试。
  • 这很混乱,并且给我们的程序增加了未使用的代码块。
  • 它确保单元测试只发生一次,而不是在发布的每个新版本中验证。

你可能会说——他可以删除它,但是他所有的单元测试工作都是徒劳的,你不会在每个版本中重用它,来改进你未来的代码,或者把你的工作片段给其他用户。

正确的方法

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

UnsplashKrisjanis Mezulis 拍摄的照片

有许多 python 测试模块,你可以为它们中的许多给出有力的论据,我喜欢 python unittest 有许多原因,它的简单快速有效,并且在标准库中!

让它工作!

  • 测试类必须从 unittest 继承。测试案例
  • 每个测试功能必须在测试 _ 中开始
  • unittest.main() 是运行来测试结果的函数。

三个小小的规则,你就有了一个合适的单元测试,很简单,不是吗?

选项

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

维多利亚诺·伊斯基耶多在 Unsplash 上拍摄的照片

不仅仅是断言相等。您可以检查任何您喜欢的东西,从数字到类型,提出正确的异常,任何您可以想象的东西,都在一个简单的标准库模块中,由 Python 开发团队维护。

最后的想法

对于每个开发人员来说,单元测试是一个必不可少的工具,Python 单元测试是一个很好的模块。

适当的单元测试将在许多方面节省你的时间,包括未来的错误,破坏同事的代码,甚至是向他人展示他们如何使用你的系统的伟大片段,这种方式增加了你编写的程序实用和有益的几率。

如果你喜欢这些文章,请发表评论,关于 Python 标准库的更多内容,请就你关心的主题发表评论,我会写下来。

我希望你喜欢它!

用 4 个步骤开始您的数据科学之旅

原文:https://towardsdatascience.com/start-your-data-science-journey-in-4-steps-f5b5a6e7e80b?source=collection_archive---------38-----------------------

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

布拉登·科拉姆在 Unsplash 拍摄的照片

开始数据科学职业生涯的自以为是的路径指南

直到 2018 年 9 月,“人工智能”这个词对我来说毫无意义。我在为皇家邮政寄信,并一如既往地好奇想学习一项不需要我付出体力的技能。编程的想法确实出现在脑海中,但我不认为我足够聪明——毕竟我是一名运动员,高中毕业后没有受过正规教育(除非你想把我的 3 级教练徽章和 BTEC 列入体育项目)。

不到两年,我获得了我认为是我人生旅程中的一个重大成就:我现在是一名顶尖的人工智能作家。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

在最初充满喜悦之后,我的思维发生了转变,在我意识到之前,我开始反思我从哪里来…

我所采取的每一项重大行动都是对困难局面的回应,但并不一定非要如此!

我收起了对编程的恐惧,事实上我已经 5 年多没有做过一点数学了,这已经不再让我担心,然而,这只是因为我失去了邮递员的工作——我没有其他选择。我在 2019 年 12 月开始了我的中道之旅,但只是因为新冠肺炎疫情让我休假,我才开始定期发帖——我需要用我的时间做一些有成效的事情,否则我只会在家里无聊,直到我被要求回到工作岗位(如果我被要求回来的话)。

意识到我被动的生活方式是不必要的费力,我决定积极主动,希望在数据科学领域有所作为。

你不需要像我一样!如果你现在正在读这篇文章**,那么你今天就有机会决定变得积极主动!在这一点上,我的目标是为你提供帮助我达到现在位置的工具,以便你可以启动你的职业生涯。**

不要等待机会,要创造机会!Kurtis Pykes

数据科学家的成就

我们经常看到成为数据科学家的先决条件,它们是多么令人生畏;精通统计学、线性代数、微积分、编程、机器学习等(名单不停)。

都是垃圾!

我是在说这些技能是不必要的吗?见鬼不!你需要具备编程知识,以及使用你选择的编程语言处理数据的能力,但是仅仅对数学有基本的了解就足以开始你的旅程。

注意:记住这篇文章是关于你职业生涯的开始

使用来自 Dataquest 的摘录,我们来定义数据科学:

提出有趣的问题,然后用数据回答这些问题的过程。一般来说,数据科学的工作流程看起来是这样的:

  • 问一个问题
  • 收集可能有助于你回答那个问题的数据
  • 清理数据
  • 探索、分析和可视化数据
  • 建立并评估一个机器学习模型
  • 传达结果

(来源: Dataquest )。

在开始之前,很容易陷入试图学习一切的困境,我会根据经验告诉你,这将是一场你无法赢得的艰苦战斗——我还没有找到人来证明我在这一点上是错的,如果是你,请留下回应。要发展成为一名数据科学家,你需要更多的数学流利度和其他专业技能,但在旅程开始时,你应该专注于培养必要的技能,让你能够迈出第一步。

1)学习一门编程语言

本世纪的辩论之一,Python 与 r。当我开始学习编程时,我选择了 Python,这只是因为这是我在 2018 年第一次开始学习编程时唯一听说过的语言。

如果让我选择今天先学习哪一个更好,我会选择更容易掌握的一个,因为它们都是非常好的选择,都有许多支持数据科学工作流的包。换句话说,把你自己暴露给这两者,然后决定你觉得哪一个更容易。

你不需要成为 Dan Bader (Python 编程专家)。你的重点应该是理解数据类型、数据结构、语法、函数、条件语句、比较、理解、循环和模块。其余的你可以随着时间的推移学习。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

(来源: LinkedIn )

资源

注意:我向 R 用户道歉,因为我只能引用我个人使用过并发现有用的东西。

学习 Python 3 | code academy——https://www.codecademy.com/learn/learn-python-3

**Python 的搭便车指南——【https://docs.python-guide.org/ **

用于数据分析的 Pythonhttps://www . Amazon . co . uk/Python-Data-Analysis-Wes-Mckinney/DP/1491957662**(这不是附属链接)**

Python 数据科学手册——https://jakevdp.github.io/PythonDataScienceHandbook/

2)学习基础数学

你需要的数学技能的程度完全取决于你想要的角色——如果你刚刚开始,很可能你会去找一个初级/实习生的角色。在此基础上,你需要的数学肯定比你想象的要少。当我开始学习数学时,我觉得它很有趣,并决定学习整个 A-Level 课程大纲,但我可以向你保证,你不需要这样做,而且非常耗时。

考虑到你对数学有很好的直觉,并且知道如何编码,那么你很好。你知道的足够多,可以获得一个初级数据科学家或实习生的职位-一旦获得这个职位,就要靠你去更深入地研究数学并建立你的数学技能,这将使你的职业生涯进一步发展。

重要的是,你要设定一个停止专注于数学的时间——大约 2-3 个月,取决于你掌握事物的速度。请记住,这是一个人们花了一生的时间来学习,但仍然无法完全攻克的课题。

"如果你不知道什么时候该停下来,你可能会永远停下来. "Kurtis Pykes

资源

可汗学院|统计——https://www.khanacademy.org/math/statistics-probability

可汗学院|微分学——https://www.khanacademy.org/math/differential-calculus

可汗学院|线性代数——https://www.khanacademy.org/math/linear-algebra

考试答案——https://www.examsolutions.net/a-level-maths/edexcel/

3)学习机器学习

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Unsplash 上由 Franck V. 拍摄的照片

如果我们遵循我按时间顺序列出的路径,那么你已经建立了我们的编程技能(我们也会使用重要的数据科学框架,如 SciPy、NumPy、Matplotlib 和 Pandas ),并且已经实践过了(即使用我们学习和/或教授的技能)。此外,你已经在必要的数学方面打下了良好的基础,所以剩下的就是学习机器学习了。

许多人直接进入深度学习,我个人认为这不是最好的事情,因为深度学习的许多基本概念都源于机器学习。也就是说,你可能想学习一些机器学习算法,下面是我要说的 5 个开始:

:维基百科和交叉验证的栈交换是上述算法的一个很好的起点。

资源

使用 Scikit-Learn 和 Tensorflow 进行机器实践学习——https://amzn.to/2ZESDEp

用 Python 进行机器学习简介——https://amzn.to/32oj6I5

机器学习(吴恩达)| Coursera——https://www.coursera.org/learn/machine-learning

深度学习专业化(作者吴恩达)| Coursera——https://www.coursera.org/learn/machine-learning

注意:机器学习课程在 Matlab 中,你可能想用你选择的语言来重现它,因为这也将是发展你的编程技能和直觉的好练习。

4)不要停止学习

永远不要停止学习!下面的链接非常符合这一点,所以我推荐阅读它们。

** [## 数据科学家如何更快地学习

学会学习的有效策略

towardsdatascience.com](/how-to-learn-faster-for-data-scientist-cfd96d317ce6) [## 学习数据科学的 3 个阶段

了解学习的 3 个阶段,以及我们如何将其有效地应用于数据科学学习

towardsdatascience.com](/3-stages-of-learning-data-science-9a04e96ba415) [## 最重要的数据科学项目

每个数据科学家都必须做的项目

towardsdatascience.com](/the-most-important-data-science-project-458d016ef8a6) [## 如何获得你真正想要的数据科学职位

当承担与人工智能相关的角色时,必须做的事情没有被充分提及

towardsdatascience.com](/how-to-secure-a-data-science-role-you-actually-want-169afc52019b) [## 为您的数据科学事业保持动力

我们可以长期保持动力。

towardsdatascience.com](/staying-motivated-for-your-data-science-career-e845f18421e1)

非常感谢你读到这个故事的结尾。如果您认为我遗漏了什么,或者您想向我指出什么,或者如果您仍然不确定什么,您的反馈是有价值的。发个回应!然而,如果你想和我联系,我在 LinkedIn 上是最活跃的,我也很乐意和你联系。

[## Kurtis Pykes -人工智能作家-走向数据科学| LinkedIn

在世界上最大的职业社区 LinkedIn 上查看 Kurtis Pykes 的个人资料。Kurtis 有一个工作列在他们的…

www.linkedin.com](https://www.linkedin.com/in/kurtispykes/)**

启动人员分析功能:3 个构件

原文:https://towardsdatascience.com/starting-a-people-analytics-function-3-building-blocks-4293ddc160f8?source=collection_archive---------40-----------------------

构建可扩展的人员分析功能的坚实基础。你必须从某个地方开始,你也可以从这里开始。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Alex Kotliarskyi 在 Unsplash 上的照片

人员分析(也称为人力资源分析、人才分析和劳动力分析)本质上是利用员工相关数据来推动业务决策。

这很流行。

数据无处不在,每一秒,每一毫秒,我们都在收集更多的数据。商业领袖已经认识到,利用他们的数据做出商业决策可能会对他们的底线产生巨大的影响。

什么类型的广告活动能产生最多的销售额?什么样的产品利润率最高?我们的目标人群在哪里购物最多?

收集数据,分析数据,然后根据这些见解做出决策已经成为一种期望。随着企业领导人越来越精通数据,迫切需要将这些原则应用到与员工相关的决策中。接下来是人员分析。

如果你想看 超级酷的例子 ,谷歌的 People Analytics 团队已经公开了他们的一些最有影响力的项目。

好吧,你被收买了。您确信 People Analytics 将改变世界,使您的业务效率提高一百万倍,并使您的员工成为这个星球上最积极参与的员工。你希望你的组织从这个新领域中获益。欢迎来到酷小子桌。

但是你从哪里开始呢?

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

照片由 rawpixel爆发时拍摄

首次开始时,请记住以下三点,这将有助于为您的人员分析功能打下坚实的基础,并迅速获得关注:

  1. 使其准确
  2. 使其可行
  3. 使其可访问

1.使它准确

在理想的情况下,所有的数据都将存储在一个集中管理的数据库中。众所周知,我们生活的世界远非理想,我们的数据通常存在于各种地方,来自各种来源,并以各种格式存在。哦,快乐。

这会让我们的工作变得复杂吗?是的。这是否让我们的工作有时令人沮丧?还有,是的。但是有几件事你可以在早期就确定下来,这会让你在将来省去很多麻烦:

  • 建立数据所有权
  • 只有一个真实的来源
  • 尽早建立信誉

建立数据所有权(或者“管理”,如果你想更花哨的话)。

有许多方法来建立数据所有权以满足您组织的独特需求。但首先,你需要确定:负责什么数据的在哪里你如何保持它安全并确保它准确

哈,就这些?!

同样,这可能看起来势不可挡,但坚持与我无畏的战士。让我们试一个例子。假设薪酬数据由财务部处理,并记录在我们的人力资源信息系统 (HRIS)中。

我们会说,财务部门的 Gracie Lou Freebush 每个月都会在我们的 HRIS 系统中运行一份报告,并将其与招聘部门签署的录取通知书进行核对。她会加密文件并保存到我们的内部服务器上。

就这样,我们建立了数据所有权!

  • Gracie Lou 负责薪酬数据的*(或“管家”)。*
  • 这些数据存放在我们的 HRIS 系统和我们的内部服务器上。
  • 我们通过对照录取通知书检查数据来确保 的准确性
  • 数据通过加密保持 安全

很简单,柠檬榨汁机。

***有单一的真理来源。*或者,有一个“资源优势等级”(我只是瞎编的但是跟我在一起)。

如果数据有出入,以什么来源为准?

让我们回到金融界的格雷西·卢。她运行了本月的报告,并根据招聘部门的聘用信检查员工的薪酬数据。

突然,她意识到维克多梅尔林有两个冲突的价值补偿!HRIS 系统的报告显示他的薪酬为 180,000 美元,而他签署的聘用信显示他的薪酬为 18,000 美元。

如果我们已经确定我们的 HRIS 在“资源优势等级”的顶端(因为 HRIS 由招聘经理、运营团队、薪资团队和法律团队审查),我们可能会得出结论,在录用函中有一个数据输入错误,也就是一个打字错误。

*在这种情况下,我们的 HRIS 通过了大多数团队的大多数批准,因此我们将它放在我们的源优势层次结构的顶部,而录取通知书到目前为止只由一个人审核。(这个例子是为了说明起见,*拜托,看在上帝的份上,对 offer letters 有多个审核步骤)。

随着人员分析的成熟,您使用越来越多的数据源(财务数据、人口统计数据、调查数据等)。等等。等等。)这变得越来越重要。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

林赛·亨伍德Unsplash 上拍摄

及早建立信誉。

当你刚开始工作时,花 80%的时间检查你的工作质量。80%.最低限度。我没开玩笑。

如果人们不信任你的数据,他们就不会信任你。

错误时有发生。同样,我们处理的数据极其复杂,在我们的分析中,微小的错误很容易泛滥成灾。你可以在 99%的时间里准确无误,但当出现错误时,人们只会注意到那 1%。

当我寄出一份包含 200 种不同计算方法的 10 页季度报告时,我从未收到过一封电子邮件说“哇,所有这些计算都绝对正确,你做得真好!”然而,我收到了(许多)类似这样的电子邮件,“第 6 页第 34 行的数字实际上应该是 7.2,而不是 7.4。”

每次收到这样的邮件,我都会少活几年。通常,报告显示的是 7.2 而不是 7.4 是有充分理由的。但是,可怕的事实是,有时给我发邮件的人是对的,但确实有错误。这是一种可怕的感觉。振作起来,查理。找一个能帮助你正确看待错误的人谈谈(我可以提供同情和虚拟拥抱),把注意力放在你学到的东西上,并在未来改变它。

当出现错误时,解释是什么导致了错误的发生,以及你采取了什么权宜之计来防止它再次发生。

以下是一些尽可能减少错误发生的方法:

  • 将数据与您之前计算的数据进行比较。今年的营业额和去年的营业额有明显的不同吗?区别有意义吗?
  • 让多人进行计算。这可能是资源密集型的,但也可能是非常有益的,尤其是在开始的时候。通过对一名新分析师这样做,我们意识到他们是用第一个月和最后一个月的平均人数来计算营业额的,而我用的是每个月的平均人数。从技术上来说,两者都可以被认为是“正确的”,但我们需要保持一致。
  • 用手算。别因为这个恨我。这是我最不喜欢做的事。我喜欢自动化,尽我所能让我的过程更有效率。为了做到这一点,我经常有模板或脚本为我进行计算。但是,我总是会选择几个部门,在那里我也会手工进行计算,以确保自动化流程按预期工作。对于那些重视效率的人来说,这可能是痛苦的,但确保准确性是如此重要。
  • 过滤检查。在查看高级结果时,发现错误可能会更加困难。在进行数据检查时,尝试查看小组的结果(例如,按部门、地点等)。)并确保他们的结果是准确的。对于小团队来说,错误更容易被发现。
  • 创建你自己的质量保证清单(这里的例子是)。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

照片由斯科特·格雷厄姆Unsplash 上拍摄

2.让它变得可行。

在 People Analytics 中,你可以做很多令人惊讶、精彩、超酷的事情,以至于你不知道从哪里开始。从最基本的开始,给人们他们需要的东西。让你的工作具有可操作性:

  • 使项目与公司目标一致
  • 有冠军
  • 提出切实的建议

项目计划的一个好方法是从现有的业务优先级和目标开始。为了让你的努力产生最大的影响,人们需要关心它,人们需要能够为此做些什么。

一个拥护者或执行发起人,是将目标放在人们关注的最前沿,让人们负起责任,并促进正在完成的工作的人。理想情况下,此人在您的组织中非常显眼,并在游戏中有一些“皮肤”(即,他们在个人或专业上有动力看到目标的实现)。

尽早让这个人加入你的项目。这应该是一种互利的关系:你帮助赞助商实现目标,赞助商帮助推广你的工作。没有执行发起人,项目会很快消亡,没有人使用、阅读或关心你的工作。悲哀。日。一个冠军可以创造一个不同的世界。**

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

照片由马太·亨利爆出

最后,你需要根据你项目的结果提出切实可行的建议**。**

当我第一次开始时,我会展示我的发现,然后期望人们前进和成功。我以为我的工作是运行分析,而他们的工作是运行分析。我会把我的发现发出去,期望世界会改变。但是,令我懊恼的是,什么都没发生。

有一个关键的差距——我正在分享我的发现,但人们仍然不知道如何与他们一起做。好吧,我们发现教育水平并不是给定职位绩效的重要指标,那又怎样?

我们需要帮助我们的观众理解,不仅仅是我们的发现,还有我们的发现意味着什么,以及他们能为此做些什么。

如果我们发现教育水平不是绩效的重要指标,这可能意味着我们应该改变该职位的选拔流程。通过扩大我们的选择标准,我们可以增加 X%的候选人数量。这也意味着我们可以通过雇佣一个教育程度较低的人来节省 Y 美元,这个人可能会有较低的报酬,但在工作上同样有效。

现在他们正在拾起你放下的东西。他们买你卖的东西。闻你煮的东西…你懂了。

3.让它变得容易理解(理想情况下,也让它变得漂亮)。

在你恐慌之前,你不必出去学一个数据可视化软件(至少现在还没有……)。这可能很简单。它可以在 Excel 中(每个人和他们的妈妈使用它是有原因的,在那个游戏中没有羞耻)。

只要让它可视化,最好是互动的。在消化视觉信息方面,人类拥有超能力。我们做得非常迅速和有效。利用我们的天赋吧!

分享您的数据时,请做到:

  • 视觉的
  • 交互式(例如使用过滤器)
  • 易于访问(例如实时数据访问)

让我们尝试以下两种体验,并思考我们的观众更喜欢哪一种:

选项 1:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Excel 中的计算表。

这里有很多信息,这可能是一件好事。如果您的受众是一直沉浸在这些数据中的人,他们可能需要这种程度的细节。但也很难从这些数据中得出有意义的结论。这里有很多,但是我在找什么呢?营业额多少才算“差”?

选项 2:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

在 Excel 中使用部门切片器组合条形图/折线图。

选项 2 是一个更直观的选项。

这非常简单,但与我们之前的情况相比,这已经是一个巨大的进步。现在,我们可以过滤到我们感兴趣的部门,我们的条形图会根据它们是高于还是低于该部门的平均月营业额来改变颜色。

我们可以立即看到,在 1 月和 4 月,营销团队的营业额比平时高。四月的营业额看起来并没有比平时高多少,但是一月的营业额确实比平时高,而且可能值得进一步调查。

例如,我们可能会发现这些人中的大多数在奖金发放后马上就离开了。为了留住我们的员工,推迟发放奖金的时间可能是值得的。

现在事情真的越来越令人兴奋了。

交互性

*领导者往往只关心与他们“相关”的数据。如果你给一个领导发全公司营业额,他们会说好吧,没问题,但是我的部门的营业额是多少?

分享数据时,重要的是让您的结果具有足够的互动性,这样领导者会觉得他们可以缩小他们认为足够具体的群体的范围

每个领导都是自己特别的雪花。有些人喜欢按部门或成本中心过滤,有些人喜欢按位置过滤,有些人甚至喜欢按不同的职位过滤。

然而,我们的工作是拯救领导者,而不是让我们的结果变得如此互动,以至于不再有意义。

首先,牢记保密性之类的事情非常重要(例如,不要显示少于 20 人的小组的结果)。当尺寸变得太小时,结果也就失去了意义。100%的离职率确实令人担忧,但如果该部门/地点/职位只有一个人,就不会如此。

帮助领导了解为什么要限制结果中的互动量,然后坚定自己的决定。

随手可得。

你可以完成有史以来最酷、最具突破性的分析。但是如果没有人看到它——如果没有人可以访问它——它就不算数。人们不能使用他们没有的东西。

让数据易于访问是数据民主化的理念。这并不意味着每个员工都应该拥有进入你的分析的所有原始数据的完全访问权。

这意味着以适当的访问级别将信息送到需要它的人手中。

大多数情况下,当更多的人有更多的机会访问数据时,好事就会发生。显然,始终要考虑隐私问题、道德问题和提供数据访问权限的潜在后果(我在和你说话,扎克伯格)。

建立人员分析功能时,决定如何分享结果至关重要。重要的考虑因素是:

  • 内容(如仪表盘、报表等。)
  • 格式(如 Excel、BI 工具、HRIS 系统等。)
  • 节奏(如每月、每季度等。)

不管你做了什么决定,一个领导者都应该确切地知道如何、在哪里以及何时可以获得他们的结果。当然,这些决策可以是反复的。开始时,您可能会每月用 Excel 发送报告,然后,随着人员分析功能的成熟,您可能会让领导实时访问 Power BI 中的仪表板。

无论你做什么,让你的数据容易消化。见鬼,让它成为一种乐趣。它会让人们回来买更多。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

来自爆发Sarah Pflug 的照片

总之,在构建人员分析功能时,首先要做到以下几点:

  1. 使其准确
    -** 建立数据所有权
    -**-拥有单一的真实来源
    -
    -尽早建立可信度
  2. 使之可行
    -** 使项目与公司目标一致
    -**-有一个拥护者
    -
    -提出切实的建议
  3. 使可访问
    -** 使用视觉效果
    -**-使其可交互
    -
    -使其易于访问

继续用你的头撞墙。变得更好了!

从零开始数据科学和分析||大学生的经历

原文:https://towardsdatascience.com/starting-data-science-and-analytics-from-scratch-the-experience-of-an-undergrad-5c6bcb83ad7b?source=collection_archive---------39-----------------------

数据科学、分析是我们都听过的时髦词汇。那么它们是什么呢?一个人如何在这个领域起步?好了,这就是我今天用这篇文章来回答的,希望你会觉得有帮助!

一个人带着对未来和职业的希望和雄心开始他们的大学生活。但是,我们从第一天开始就知道我们对什么有热情吗?我没有。我总是随波逐流,尝试新事物。但是随波逐流并不总是最好的决定,如果你能找到一些指导,这真的很有帮助。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

克里斯里德在 Unsplash 上的照片

所以根据维基百科的说法,数据科学是一个统一统计学、数据分析、机器学习以及它们的相关方法的概念,以便用数据来理解和分析实际现象。我们知道,这不是一个最近才出现的新领域,也不是一个独立的实体,而是先前存在的领域的融合。

你需要做的第一件事是在统计学和概率学上建立一个坚实的基础。你必须在描述统计学、概率分布、假设检验、回归、条件概率、贝叶斯定理和可视化方法方面打下坚实的基础。

在这方面,我遇到的最好的书之一是谢尔登·m·罗斯的《工程师和科学家的概率和统计》。你也可以看看印度作家写的类似的书。语言要简单得多,它被 H.C. Taneja 称为“工程和科学的统计方法”。

现在你对数学概念有了很好的理解,让我们来看看语言和工具。

了解 Python 或 R 并不是唯一重要的事情。有各种各样的工具有它们自己不同的应用,像 MySQL,MS Excel,PowerBI,Tableau 等等。

申请分析或数据科学工作时,拥有多样化的技能很重要。

鉴于 Python 和 R 是数据科学中最流行的两种语言,您不需要同时了解这两种语言。如果需要的话,在一个领域拥有专长可以帮助你过渡到另一个领域。我使用 Python,唯一的原因是我是从这个开始的,现在我已经适应了这个环境。所以,下载环境,我用的是 Jupyter 笔记本。开始探索它,做一个基础课程或者查看 YouTube 上关于基础的惊人资源,以便掌握语言、语法和环境。

你不需要去上专门的课程,随着学习的深入,你会学到更多关于这门语言的知识。

一旦你掌握了这门语言,我们就进入实现部分。要开始数据科学,你需要数据。你从哪里得到数据?

我的 go to source 是 Kaggle ,它有针对不同专业水平的各种数据,这些数据可以根据你想要应用的概念进行搜索。

谷歌有自己的数据集搜索引擎,datasetsearch.research.google.com,当你的搜索是数据集特定的而不是技能特定的时候,这就更有用了。

获取数据并不局限于这些来源。你也可以从你自己的来源挖掘数据,你可以从在线平台下载,比如 Twitter,Reddit 等。

一旦你有了数据,你不只是开始建立模型和做出预测。第一步是清理数据。真实世界的数据是肮脏的。您需要将数据转换成您可以使用的形式。

有各种各样的事情需要做。有许多缺失值,您必须看看是否要删除这些行,或者对这些值进行假设-您会假设它是其余值的平均值还是中值等等。您可能需要添加、删除或拆分某些列。有些字符串可以转换成 float 或 int。这些任务取决于数据是什么、数据的用途以及数据有多脏。

接下来,我们做最有趣和最有见地的部分,我们探索数据。显而易见的第一步是计算一些汇总统计数据。你想知道你有多少个数据点,最小值和最大值,平均值,标准偏差。因此你首先会发现描述性统计。

然后我们开始可视化数据。有各种各样的图表可供选择——条形图、直方图、箱线图、散点图等。你可以画出单个的属性来理解分布,或者你可以画出每个变量与可依赖变量的关系来理解相关性。

对于多个属性,您可能希望找到各种属性之间的相互关系。一种简单的方法是使用相关矩阵。

这整个过程被称为“数据探索和可视化”。这是一个庞大的过程,绝不仅限于这些任务。这是重要的一步,因为不知道数据,你就不知道要建立什么样的模型。我可以就这个话题写一整篇文章。

接下来,我们了解我们想要对数据做什么。我们对自己在寻找什么有明确的想法吗?我们有这方面的训练数据吗?

如果是,我们可以对数据应用监督学习技术,如回归、分类等。

否则,我们使用无监督技术让数据自己说话。

这些技术中的每一种都要求你很好地理解它们背后的数学概念。一旦完成这一步,你需要学习各种机器学习算法。例如,在单独回归的情况下,单独的线性回归不适合所有类型的数据,因此我们有多项式回归、随机森林回归等。

但是仅仅知道算法是不够的,你需要知道如何将它们用于数据,也就是如何将它们融入你的代码中。所有这些算法都可以在 Python 库中找到。有些时候你可以直接使用算法,有些时候你需要调整它。

所以第一步:作为初学者,学习有广泛应用的基本算法。这些包括但不限于线性回归、逻辑回归、朴素贝叶斯、k-最近邻、k-均值、主成分分析。

为了了解它们是什么,它们是如何工作的,我看了每一个的 youtube 视频。这只会让你对工作有所了解。

第二步:将它应用到您的数据中。除非你使用算法,否则你不会有效地学习。数据科学不是关于概念的理论知识。

数据科学需要哪些机器学习算法?这些算法是如何分类的?各种技术的不同算法是什么?这些是另一篇文章的问题。

在我结束这篇文章之前,我想根据我的经验给出一些重要的提示:

  1. 多花点时间在编码部分,而不是学习部分。它们是平行的过程——同时学习和应用。不要等到理论概念讲完。
  2. 承担多个小项目,而不是一个大项目。小项目会花费更少的时间,给你成就感,你会学到更多的东西。
  3. Kaggle 不仅保存数据,还保存其他用户的各种笔记本。最初,您可以使用它来理解要采取的方法,但不要复制代码。
  4. 如果你被困住了,不要失去希望,你不知道的,网上有人知道。搜索你的问题,你会惊讶地发现有多少人遇到过类似的情况。

如果你还想知道更多,或者你对这篇文章或即将发表的文章有一些建议,你可以通过 LinkedIn 与我联系。

在新冠肺炎期间开始数据科学

原文:https://towardsdatascience.com/starting-data-science-during-covid-19-199931a6f902?source=collection_archive---------67-----------------------

我学到了什么

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

马库斯·斯皮斯克在 Unsplash 上的照片

自学一项新技能并不容易。

为了事业自学一套新的技能,绝对不容易。

自学是一种承诺,需要专注和奉献,最重要的是,时间

如果你正在阅读这篇文章,我会假设你很有可能在某个时候听说过数据科学家被归类为 21 世纪最性感的工作**。你在谷歌上搜索,看到各种来源的报告称,目前数据科学家短缺,需求将继续快速增长。在你的研究过程中,你发现了吸引每个人注意力的主要东西,他们的薪水。在浏览互联网寻找成为数据科学家所需的一些先决条件时,您开始注意到一些趋势,例如:**

  • Python 中的知识
  • 结构化查询语言
  • 统计数字
  • 线性代数
  • 离散数学
  • 结石
  • 机器学习
  • 拥有硕士或博士学位

这个清单还在继续。

突然之间,“21 世纪最性感的工作”听起来像是要花一个世纪的时间才能获得这项工作的技能。

还是会?

时间是我们生命中最重要的东西。回到我上面提到的列表,许多人开始远离学习数据科学,因为他们没有时间去学习一切。

这是百分之百可以理解的。大多数对学习数据科学感兴趣的人无法仅仅离开生活几个月到一年来学习所有这些复杂的主题。我也是有同样问题的人之一,但是后来新冠肺炎来了。

我的故事

新冠肺炎迫使我们许多人(包括我自己)呆在家里,让许多人失业。起初,我对自己说“我应该利用这段自我隔离的时间,最终学会数据科学”。

说起来容易做起来难。

自学一项新技能并不容易。

学习一项新技能,尤其是在当前的世界形势下,由于新冠肺炎和乔治·弗洛伊德被恐怖杀害后在世界范围内点燃的大规模抗议活动。这是一个很难集中注意力和学习的时期,尤其是对我来说,作为一名年轻的非裔美国男性,我目睹了社交媒体上爆发的一切。

然而,在无数次尝试学习数据科学之后,我现在终于看到了进步,为我自己在这个领域的成功铺平了道路。

在过去的两年里,我断断续续地试图学习这门学科。我尝试过各种 MOOC,比如 DataCamp、Coursera、Codecademy、Udacity 等等。

虽然我在学习时理解了这些网站上教授的主题,但我从未能够记住这些信息。我一点也不想诋毁这些网站。它们是非常好的学习资源,许多人利用它们获得了成功。我不是他们中的一员,而需要一种不同的方式。我会学到一些东西,然后第二天就忘了怎么做。这是一个重复的循环,我完成了模块,但没有感觉到我学到了什么。

四月初的某一天,我在 YouTube 上遇到了一位名叫 Ken Jee 的数据科学内容创作者。我看了他的第一个视频,我记得他说过学习数据科学的最佳方式是做项目。

就在那一刻,我的脑海里突然灵光一现。

我在他的 YouTube 频道上浏览了他的一个播放列表,在那里他讲述了如何从项目规划阶段到部署模型来处理一个数据科学项目。我彻底地看完了他的教程系列,并把它作为我自己的项目重新创建。我不仅学到了东西,而且我正在实施它们并将这些概念应用到一个真实的项目中。通过这样做,我开始一点一点地保留我所做的事情。

突然间,事情开始变得有意义了。

在开发我的第一个项目时,我偶然发现了另一个数据科学内容创作者,名叫 Chanin Nantasenamat ,他在自己的 YouTube 频道上化名为 Data Professor。他创建了一个关于如何用 Hugo 和 GitHub 页面制作数据科学作品集网站的教程,我照着做了。这是一个巨大的信心助推器,因为我现在有一个可视化平台来展示我的项目,因为我完成了它们。我会把成品 链接到这里 给那些对它的样子很好奇的人。我最喜欢 Chanin 在他的视频结尾经常说的一句话是“学习数据科学的最好方法是做数据科学”。****

未来计划

我现在正在进行我的第二个项目,规划我的第三个项目,并开始在毕马威(KPMG)进行虚拟数据分析实习。我之所以想写这篇文章,是因为我想分享我是如何开始走向成功的故事,因为我现在正在做来激励你。世界正在快速变化,与其在以后讲述我是如何做到的,我想现在就写下来,现在作为我正在努力实现我的目标,并告诉你如果你还没有开始你的数据科学之旅,现在还为时不晚。****

我将继续记录我的故事和前进的进程。请随时关注我,并留下来了解我和我的旅程。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值