zoukankan      html  css  js  c++  java
  • pandas 轴索引的重命名,离散化,异常值的处理与随机方法

    一、重命名轴索引

    与Series对象类似,轴索引也有一个map方法:

    In [83]: df = pd.DataFrame(np.arange(12).reshape((3, 4)),
        ...:                     index=['Ohio', 'Colorado', 'New York'],
        ...:                     columns=['one', 'two', 'three', 'four'])
        ...:
    In [84]: transform = lambda x: x[:4].upper() # 截取前4个字符并大写
    In [85]: df.index.map(transform) # map的结果
    Out[85]: Index(['OHIO', 'COLO', 'NEW '], dtype='object')
    In [86]: df.index = df.index.map(transform) #用结果修改原来的index
    In [87]: df
    Out[87]:
          one  two  three  four
    OHIO    0    1      2     3
    COLO    4    5      6     7
    NEW     8    9      10    11

    还可以使用rename方法修改索引,且不修改原数据:

    # 参数的值是对索引进行修改的处理函数,比如str.title
    In [88]: df.rename(index=str.title, columns=str.upper)
    Out[88]:
          ONE  TWO  THREE  FOUR
    Ohio    0    1      2     3
    Colo    4    5      6     7
    New     8    9     10    11
    In [89]: df # 原值未变
    Out[89]:
          one  two  three  four
    OHIO    0    1      2     3
    COLO    4    5      6     7
    NEW     8    9     10    11

    或者使用字典的方式,将指定的索引重命名为新值:

    In [90]: df.rename(index={'OHIO': 'INDIANA'},
        ...:             columns={'three': 'peekaboo'})
        ...:
    Out[90]:
             one  two  peekaboo  four
    INDIANA    0    1         2     3
    COLO       4    5         6     7
    NEW        8    9        10    11
    In [91]: df
    Out[91]:
          one  two  three  four
    OHIO    0    1      2     3
    COLO    4    5      6     7
    NEW     8    9     10    11

    照样可以使用inplace=True修改原数据集。

    二、离散化

    离散化,就是将连续值转换为一个个区间内,形成一个个分隔的‘箱子’。假设我们有下面的一群人的年龄数据,想将它们进行分组,并放入离散的年龄箱内:

    ages = [20, 22, 25, 27, 21, 23, 37, 31, 61, 45, 41, 32]

    我们预先定义18~25、26~35、36~60以及61及以上等若干组。

    Pandas提供一个cut方法,帮助我们实现分箱功能:

    In [93]: bins = [18,25,35,60,100]
    In [94]: cats = pd.cut(ages,bins)
    In [95]: cats
    Out[95]:
    [(18, 25], (18, 25], (18, 25], (25, 35], (18, 25], ..., (25, 35], (60, 100], (35, 60], (35, 60], (25, 35]]
    Length: 12
    Categories (4, interval[int64]): [(18, 25] < (25, 35] < (35, 60] < (60, 100]]

    返回的cats是一个特殊的Categorical对象,输出描述了12个年龄值分别处于哪个箱子中。cats包含一系列的属性:

    In [96]: cats.codes
    Out[96]: array([0, 0, 0, 1, 0, 0, 2, 1, 3, 2, 2, 1], dtype=int8)
    In [97]: cats.categories
    Out[97]:
    IntervalIndex([(18, 25], (25, 35], (35, 60], (60, 100]]
                  closed='right',
                  dtype='interval[int64]')
    In [98]: cats.describe
    Out[98]:
    <bound method Categorical.describe of [(18, 25], (18, 25], (18, 25], (25, 35], (18, 25], ..., (25, 35], (60, 100], (35, 60], (35, 60], (25, 35]]
    Length: 12
    Categories (4, interval[int64]): [(18, 25] < (25, 35] < (35, 60] < (60, 100]]>
    In [99]: pd.value_counts(cats)  # 各个箱子的数量
    Out[99]: 
    (18, 25]     5
    (35, 60]     3
    (25, 35]     3
    (60, 100]    1
    dtype: int64

    分箱的区间通常是左开右闭的,如果想变成左闭右开,请设置参数right=False。

    可以定义labels参数,来自定义每种箱子的名称:

    In [100]: group_names = ['Youth', 'YoungAdult', 'MiddleAged', 'Senior']^M
         ...: pd.cut(ages, bins, labels=group_names)
    Out[100]:
    [Youth, Youth, Youth, YoungAdult, Youth, ..., YoungAdult, Senior, MiddleAged, MiddleAged, YoungAdult]
    Length: 12
    Categories (4, object): [Youth < YoungAdult < MiddleAged < Senior]

    如果你不提供分箱的区间定义,而是直接要求分隔成整数个等分区间,可以这么做:

    In [101]: d =np.random.rand(20)
    In [102]: d
    Out[102]:
    array([0.83732945, 0.0850416 , 0.66540597, 0.90479238, 0.99222014,
           0.39409122, 0.91896172, 0.87163655, 0.31374598, 0.27726111,
           0.7716572 , 0.79131961, 0.42805445, 0.29934685, 0.19077374,
           0.79701771, 0.93789892, 0.93536338, 0.32299602, 0.305671  ])
    In [103]: pd.cut(d, 4, precision=2) # 精度限制在两位
    Out[103]:
    [(0.77, 0.99], (0.084, 0.31], (0.54, 0.77], (0.77, 0.99], (0.77, 0.99], ..., (0.77, 0.99], (0.77, 0.99], (0.77, 0.99], (0.31, 0.54], (0.084, 0.31]]
    Length: 20
    Categories (4, interval[float64]): [(0.084, 0.31] < (0.31, 0.54] < (0.54, 0.77] < (0.77, 0.99]]

    cut函数执行的时候,分箱区间要么是你指定的,要么是均匀大小的。还有一种分箱方法叫做qcut,它是使用样本的分位数来分割的,而不是样本值的大小。比如下面的操作,将使每个箱子中元素的个数相等:

    In [104]: data = np.random.randn(1000)
    In [105]: cats = pd.qcut(data,4)
    In [106]: cats
    Out[106]:
    [(0.644, 2.83], (-0.0344, 0.644], (-0.0344, 0.644], (-0.734, -0.0344], (-0.734, -0.0344], ..., (-3.327, -0.734], (-0.734, -0.0344], (0.644, 2.83], (-0.734, -0.0344], (-0.0344, 0.644]]
    Length: 1000
    Categories (4, interval[float64]): [(-3.327, -0.734] < (-0.734, -0.0344] < (-0.0344, 0.644] < (0.644, 2.83]]
    In [108]: pd.value_counts(cats) # 各箱子中的元素个数相同
    Out[108]:
    (0.644, 2.83]        250
    (-0.0344, 0.644]     250
    (-0.734, -0.0344]    250
    (-3.327, -0.734]     250
    dtype: int64

    qcut还可以自定义0~1之间的分位数:

    pd.qcut(data, [0, 0.1, 0.5, 0.9, 1.])

    离散化函数对于分位数和分组分析特别有用。

    三、异常值处理

    检测和过滤异常值是数据清洗过程中非常重要的一步。比如你手里有个一万成人的身高数据,其中有几个3m以上,1m以下的数据,这都是属于异常值,需要被过滤掉。

    我们来看下面的一组正态分布的数据:

    In [109]: df = pd.DataFrame(np.random.randn(1000, 4))
    In [110]: df.describe()
    Out[110]:
                     0            1            2            3
    count    1000.000000    1000.000000   1000.000000  1000.000000
    mean       -0.001764       0.023018      0.038956     0.016735
    std         0.998835       1.041113      1.025342     1.019077
    min        -3.035805      -3.056706     -2.857154    -2.922755
    25%        -0.654426      -0.695994     -0.712627    -0.702766
    50%        -0.005015       0.011862      0.020562    -0.041231
    75%         0.660182       0.683478      0.732590     0.758038
    max         3.323073       3.701470      3.280375     3.997876

    如果你想找出第二列数据中绝对值大于3的元素:

    In [113]: col = df[2]
    In [114]: col[np.abs(col) > 3]
    Out[114]:
    30     3.091161
    113    3.280375
    Name: 2, dtype: float64

    如果要选出所有行内有值大于3或小于-3的行,可以使用下面的any方法搭配:

    In [125]: df[(np.abs(df)>3).any(1)]
    Out[125]:
                0         1         2         3
    28      0.008674    0.046048 -0.171580  3.997876
    30      0.709758   -1.871982  3.091161 -0.819429
    113     0.432223   -0.675313  3.280375  0.841355
    169     3.323073   -0.608988  0.685795 -0.710693
    177    -1.514524   -3.056706 -0.760937  1.300434
    322     3.296765    0.971996  0.114804  1.855576
    410     3.246140   -0.039501  1.530122  1.502243
    496    -3.035805   -0.535662  0.703911  0.916483
    575    -0.127245    3.701470 -0.642512  0.281001
    720     3.045646    1.266809  1.263198  1.429049
    799     0.523183   -0.246954  1.132868  3.141117

    首先,我们对整个df取绝对值,然后和3比较,形成一个bool的DataFrame,再使用any在行方向(参数1的作用)进行判断是否有True的存在,如果有,则保存在一个Series中,最后,用这个Series作为行号取df取出对应的行。

    我们还可以将绝对值大于3的数分别设置为+3和-3,只需要使用np.sign(x)函数,这个函数根据x的符号分别生成+1和-1:

    In [127]: df[np.abs(df) > 3] = np.sign(df) * 3
    In [130]: df.describe()
    Out[130]:
                     0            1            2            3
    count    1000.000000    1000.000000   1000.000000  1000.000000
    mean       -0.002640       0.022374      0.038584     0.015596
    std         0.995851       1.038699      1.024224     1.015232
    min        -3.000000      -3.000000     -2.857154    -2.922755
    25%        -0.654426      -0.695994     -0.712627    -0.702766
    50%        -0.005015       0.011862      0.020562    -0.041231
    75%         0.660182       0.683478      0.732590     0.758038
    max         3.000000       3.000000      3.000000     3.000000
    In [133]: (np.sign(df)*3).head()
    Out[133]:
         0    1    2    3
    0   3.0   3.0 -3.0 -3.0
    1   3.0   3.0 -3.0 -3.0
    2  -3.0  -3.0 -3.0 -3.0
    3  -3.0  -3.0  3.0 -3.0
    4   3.0  -3.0  3.0 -3.0

    四、随机抽样

    有时候,我们需要打乱原有的数据顺序,让数据看起来像现实中比较混沌、自然的样子。这里推荐一个permutation操作,它来自numpy.random,可以随机生成一个序列:

    In [134]: order = np.random.permutation(5) # 5个数
    In [135]: order
    Out[135]: array([3, 4, 1, 2, 0])

    然后我们用它处理下面的df,让行的顺序变成和order的一样:

    In [136]: df = pd.DataFrame(np.arange(5 * 4).reshape((5, 4)))
    In [137]: df
    Out[137]:
        0   1   2   3
    0   0   1   2   3
    1   4   5   6   7
    2   8   9   10  11
    3   12  13  14  15
    4   16  17  18  19
    In [138]: df.take(order)  #
    Out[138]:
        0   1   2   3
    3   12  13  14  15
    4   16  17  18  19
    1    4   5   6   7
    2    8   9  10  11
    0    0   1   2   3
    In [139]: df.iloc[order]  # 同上
    Out[139]:
        0   1   2   3
    3   12  13  14  15
    4   16  17  18  19
    1    4   5   6   7
    2    8   9  10  11
    0    0   1   2   3

    可以看到,通过take函数,使用order作为参数,打乱了df的行顺序。

    还有一种叫做抽样的操作,从原样本集合中抽取一部分形成新的样本集合,分重复抽样和不重复抽样。pandas提供的sample函数帮我们实现了这一功能:

    In [140]: df.sample(n=3)
    Out[140]:
        0   1   2   3
    0   0   1   2   3
    4   16  17  18  19
    1   4   5   6   7
    In [141]: df.sample(n=10)
    ---------------------------------------------------------------------------
    ValueError                                Traceback (most recent call last)
    In [142]: df.sample(n=10,replace=True)
    Out[142]:
        0   1   2   3
    3   12  13  14  15
    2    8   9  10  11
    2    8   9  10  11
    0    0   1   2   3
    3   12  13  14  15
    0    0   1   2   3
    2    8   9  10  11
    4   16  17  18  19
    1    4   5   6   7
    3   12  13  14  15
    • n=3:指定从原来数据中抽取3行
    • n=10:弹出异常,因为原数据不够10行
    • replace=True:可以重复抽取,这样10行可以,因为有重复

    很明显,取样的操作是针对每行的。前面我们说过,一行就是一条记录,一个样本。

  • 相关阅读:
    【转】HTML CANVAS
    【转】JY 博客
    【转发】如何使用NPM?CNPM又是什么?
    【转廖大神】package.json 包安装
    【转】Socket接收字节缓冲区
    C# 串口操作系列(5)--通讯库雏形
    C# 串口操作系列(3) -- 协议篇,二进制协议数据解析
    C# 串口操作系列(4) -- 协议篇,文本协议数据解析
    .netCore微服务使用Nginx集中式管理实现
    nginx代理访问及上传文件异常413 Request Entity Too Large
  • 原文地址:https://www.cnblogs.com/lavender1221/p/12730311.html
Copyright © 2011-2022 走看看