Pandas数据处理与特征提取

作者: leobupt | 来源:发表于2018-05-11 16:22 被阅读39次

    1. 目的

    了解使用pandas数据处理。
    下面操作相对复杂些, 主要整理给自己看, 写的比较粗糙.
    如果那些看不明白, 可以留言标出来, 我会花些时间整理.

    1.1 数据样例:

    User_id,Merchant_id,Action,Coupon_id,Discount_rate,Date_received,Date
    13740231,18907,2,100017492,500:50,20160513,null
    13740231,34805,1,null,null,null,20160321
    14336199,18907,0,null,null,null,20160618
    15137031,25104,2,100120354,150:50,20160613,null
    15137031,44706,2,100071973,50:5,20160317,null

    1.2 字段说明

    • Coupon_id: 优惠券ID:null表示无优惠券消费,此时Discount_rate和Date_received字段无意义
    • Discount_rate: 优惠率:x \in [0,1]代表折扣率;x:y表示满x减y。单位是元
    • Distance: user经常活动的地点离该merchant的最近门店距离是x*500米(如果是连锁店,则取最近的一家门店),x\in[0,10];null表示无此信息,0表示低于500米,10表示大于5公里;
    • Date_received: 领取优惠券日期
    • 消费日期:如果Date=null & Coupon_id != null,该记录表示领取优惠券但没有使用,即负样本;如果Date!=null & Coupon_id = null,则表示普通消费日期;如果Date!=null & Coupon_id != null,则表示用优惠券消费日期,即正样本;

    1.3 环境准备

    import pandas as pd
    df = pd.read_csv("example.csv")
    

    2. 数据处理

    2.1 列变换

    2.1.1 单列变换

    • 针对单列进行null 替换, 生成新列
    df['newDate'] = df.Date.replace("null", 0)
    
    # Date列, 分段映射
    def mapDate(x):
        if(x=="null"):
            return 0
        elif(x<=20160501):
            return 1
        else:
            return 2
    df.Date.apply(lambda x: mapDate(x))
    df['Action'].apply(lambda x: 1 if (x>=0 and x<=15) else 0)
    
    • 计算折扣率
    In [28]: def discountFuc(x):
       ....:         list_discount = x.split(":")
       ....:         if(x=="null"):
       ....:                 return 0.1
       ....:         elif(len(list_discount)==2):
       ....:                 return round(float(list_discount[1]) / float(list_discount[0]), 3)
       ....:         else: 
       ....:                 return list_discount[0]
       ....:     
    
    In [29]: df.Discount_rate.apply(lambda x: discountFuc(x))
    Out[29]: 
    0    0.100
    1    0.100
    2    0.100
    3    0.333
    4    0.100
    Name: Discount_rate, dtype: float64
    
    • 求满折扣的阈值, 映射函数
    def setMax(x):
        l = x.split(":")
        if(len(l)==2):
            return l[0]
        else:
            return 100
    
    • 求满减的值, 映射函数
    def setMin(x):
        l = x.split(":")
        if(len(l)==2):
            return l[1]
        else:
            return 100*(1-float(l[0]))
    
    • 列字符串切割
    df.Discount_rate.str.split(':', expand=True)[1].astype('float32')
    
    • 单列拆分多列
    # 如下列,分割两列
    df.head()
    >>>
    20180101:2010101
    20180102:2010102
    
    # 定义拆分函数:
    def splitD(x):
        if x=='null':
            return 0, 0
        elif x.find(':')>=0:
            maxValue = x.split(':')[0]
            minValue = x.split(':')[1]
        else: # 其他取默认值
            maxValue = 50
            minValue = 50*float(x)
        return maxValue, minValue 
    
    # 如下,进行拆分:
    # 注意: index=df.index, 目的是保证新产生的df与原来index一致, 方便后面concat等
    df[['maxValue', 'minValue']] = pd.DataFrame(df.Discount_rate.apply(lambda x: splitD(x)).values.tolist(), index=df.index, dtype='int32')
    

    2.1.2 两列合并

    • 两列直接相加
    df.User_id + df.Merchant_id
    
    • 两列通过函数映射整合
    # 如: 某些列满足某种条件, 返回某值
    df['result'] = df.apply(lambda x: x.User_id if x.Date=='null' else x.Merchant_id, axis=1).astype('float32')
    
    • 对于多列合并的重复操作,提取函数:
    # 两列相除, 可能存在N对,避免重复代码,也可写成方法:
    def getRate(df, xStr, yStr):
        return df[yStr] / (df[xStr] + 0.01) # 0.01避免分母为0
    
    # 利用上面函数,比较方便的整合两列相除的问题
    getRate(df, 'col1', 'col2')
    

    2.2 去重

    • 去重汇总
    df.nunquie()
    
    • 去重显示
    df.User_id.drop_duplicates().head()
    
    • 去重后统计
    # 如下: 实现 select v1, v2, count(distinct merchant_id) from t1 group by v1, v2
    # 先对User_id, Merchant_di进行groupby
    df.groupby(['User_id', 'Merchant_id'])['User_id'].count().reset_index(name='count1')[['User_id', 'Merchant_id']].groupby('User_id')['Merchant_id'].count().reset_index(name='mid_count')
    

    2.3 排序

    • 按某列排序
    df.sort_values(by='User_id', ascending=False).head()
    
    • 某列分组后排序
    # reset_index函数
    df[df['Date_received'].astype(str)!='null'].groupby(['User_id'])['Date_received'].count().reset_index(name='count').sort_values(by='count', ascending=False).head()
    

    2.4 空值

    • 检查某列是否有空值
    df.iloc[2,0] = np.nan
    np.isnan(df.User_id).any()
    np.isnan(df.User_id)
    
    • 过滤掉含有空的行
    df_tmp[~df_tmp.columnname.isnull()]
    
    • 空置填充
    # 可以先根据已知的值, 对应行样本, 训练后预测未知的值;
    # 最后填充, 方法:
    df.loc[ (df.Age.isnull()), 'Age'] = predictAge
    
    # 再看其他填充样例:
    df2 = pd.DataFrame(np.random.randint(2,10,3))
    df2.loc[0:1,0] = 1090  # 结果: 替换掉前两个
    # df2.loc[0:2,0] = 1090 # 尝试看下不同案例. 结果:替换掉
    # df2.loc[1,0] = 1090 # 尝试看下不同案例. 结果:替换掉第1个
    
    

    2.5 列属性转换

    • 类型转换
    a = [['a', '1.2', '4.2'], ['b', '70', '0.03'], ['x', '5', '0']]
    df = pd.DataFrame(a, columns=['one', 'two', 'three'])
    df
    Out[16]: 
      one  two three
    0   a  1.2   4.2
    1   b   70  0.03
    2   x    5     0
    
    df.dtypes
    Out[17]: 
    one      object
    two      object
    three    object
    df[['two', 'three']] = df[['two', 'three']].astype(float)
    
    # pandas提供针对df整体类型转化方法:
    df2 = df.convert_objects(convert_numeric=True)
    df2.dtypes
    .. float64
    .. float64
    
    • 重命名: rename官方文档
    # 重命名某些列
    df.rename(index=str, columns={0:'click_times', 1:'pay_times', 2:'get_times'})
    

    2.6 groupby

    # groupby Userid, partValue
    # 注意: reset_index 用法将group结果列命名为count
    df_new = df[df.Coupon_id!='null'].groupby(['User_id', 'partValue'])['Merchant_id'].count().reset_index(name='count').head()
    >>>
        User_id partValue   count
    0   4   0-50    1
    1   35  0-50    1
    2   35  200-500 1
    3   35  50-200  2
    4   36  0-50    2
    
    # 将列partValue透视到行上,每个值作为一列
    df_new.pivot_table(values='count',index='User_id', columns='partValue', fill_value=0).head()
    >>>
    partValue   0-50    200-500 50-200
    User_id         
    4   1   0   0
    35  1   1   2
    36  2   0   0
    
    • 分组汇总: 对一列实行多种汇总方式
    # groupby User_id后,每组中对discountRate进行三种不同函数运算
    df_new = df.groupby('User_id')['discountRate'].agg({'discount_avg':np.average, 'discount_max':np.max, 'discount_min':np.min})
    >>>
        discount_avg    discount_max    discount_min
    User_id         
    4   0.833389    0.833389    0.833389
    35  0.800128    0.900005    0.500500
    36  0.791757    0.833389    0.750125
    64  0.900010    0.900010    0.900010
    110 0.900008    0.900010    0.900005
    
    # 将df_new的index转换成新列
    df_new.reset_index(level='User_id')
        User_id discount_avg    discount_max    discount_min
    0   4   0.833389    0.833389    0.833389
    1   35  0.800128    0.900005    0.500500
    2   36  0.791757    0.833389    0.750125
    3   64  0.900010    0.900010    0.900010
    4   110 0.900008    0.900010    0.900005
    
    # agg后面的函数,可以尝试自定义函数
    # 商家优惠券被领取后不核销次数: get_times_noconsume
    def getTimesNoConsume(df):
        return df[df.Action==2].Action.count()
    
    # 商家优惠券被领取后核销次数: get_times_consume
    def getTimesConsume(df):
        return df[df.Action==1].Action.count()
    
    df.groupby('Merchant_id')['Action' , 'User_id'].agg({'get_times':getTimes, 'get_times_noconsume':getTimesNoConsume, 'get_times_consume':getTimesConsume})
    

    2.7 过滤

    # 通过index进行过滤
    df.filter(items=[184, 417, 687], axis=0)
    
    • 列过滤
    # 通过对某列的值进行过滤
    df[df.col1>v]
    
    # 通过正则匹配列名, 进行过滤
    # 如下: 过滤, column name 为"Survived" 或者 "Age_" 开头或者 "Fare_"开头
    df.filter(regex='Survived|Age_.*|Fare_.*')
    
    • 过滤np.nan
    df[~np.isnan(df.date_received)].count()
    
    • 根据B列过滤A列
     dff.A[pd.notnull(df.B)]
    

    2.8 删除列

    # 删除列,返回新的df
    df.drop(['NewDistance'], axis=1)
    # 直接在df上删除列
    del df['NewDistance']
    

    2.9 创建DataFrame

    • Series生成:
    dict_s0 = {'S': 10, 'C': 11, 'Q': 12, 'S1':100}
    dict_s1 = {'S': 1, 'C': 2, 'Q': 3}
    s0 = pd.Series(dict_s0)
    s1 = pd.Series(dict_s1)
    # 生成DataFrame, 会按照索引来进行, 如下对比, 可一目了然
    df2 = pd.DataFrame({'s0':s0, 's1':s1})
        s0  s1
    C   11  2.0
    Q   12  3.0
    S   10  1.0
    S1  100 Na
    

    3.多个DataFrame运算

    3.1 表关联: join | merge | concat

    • 多个表join的简单写法
    # df_list包含多个df, 通过相同的key进行join
    df_list = [df1, df2, df3, df4]
    df_join_more = reduce(lambda left,right: pd.merge(left,right,on='User_id', how='left').fillna(0), df_list)
    

    4. 重复代码提取

    • 重复的groupby
    # 抽取重复代码
    def getFeature2(df, groupby_col, agg_col, rename_col):
        return df.groupby(groupby_col)[agg_col].apply(np.average).reset_index(name=rename_col)
    
    # 下面直接根据需要调用即可
    getFeature2(df, 'Coupon_id', 'date_received_week_day', 'avg_week_day')
    

    相关文章

      网友评论

        本文标题:Pandas数据处理与特征提取

        本文链接:https://www.haomeiwen.com/subject/yzzucftx.html