zoukankan      html  css  js  c++  java
  • 我的Pandas应用场景(2)

    上文交代了一些啰嗦事,本文开始,就要来点实际的了。

    先来一个比较简单的场景:

    Given:一个包括N(极其复杂,这里取3个)个列的DataFrame:df,df包括index;

    And:对df所有列元素进行一些处理,得到df的一个变换后的df_new;

    And:对df_new的某些列做极其复杂的判断,得到新的列result;

    When:需要将要根据result对df进行分析;

    Then:将result追加到df中。

    上述的场景是我的一个算法验证的场景,简单地说,就是需要通过对原始数据进行变换,然后得到新的列,然后追加到原始数据中,最后进行分析。

    首先构造一下模拟的数据吧。我们的数据通过随机数产生,为10*3的数据,每一列的名称为A/B/C,放到csv格式的文件中,文件内容如下所示:

    A,B,C
    4.556325895482557,4.9467487190814206,9.240498646959768
    6.798122785026925,9.205498509979439,6.495701755638054
    1.7088666262153485,1.9490481646738644,5.016719349132167
    7.68793618140002,4.288529993589748,0.4479283787649413
    0.22238136867848257,2.861119654701667,5.296500633944277
    3.8352546975711,0.29287579880826087,1.0438719791356377
    4.603712955967749,5.647815101448938,0.6054047619225811
    6.916870514198006,8.903690009637602,4.836793019361064
    9.845396552800361,0.8159084013183737,0.8425827491512894
    2.425545747141858,7.353661205806686,2.982326067390466
    

    一般字符型的文件会以上述的逗号隔开的方式存储,通过pandas的read_csv()可以方便的读入数据到DataFrame,如下代码所示:

    import pandas as pd
    import numpy as np
    
    df = pd.read_csv('d:/data.csv')

    pd.read_csv()默认的读法就是上述代码那样,他会将第一行当做列名读入。假如我们的csv数据中不包含列名,可以通过header=None来禁止将第一行当做列名;假如csv数据中没有列名,而我们想要指定列名,这也是我经常做的,可以通过name=[]参数,通过一个列表指定所有列的名称。指定列名有一个好处就是列名可以当做DataFrame的属性,对列进行访问,后续会介绍。

    读进来的输入如下所示:

    然后,我们需要对df进行变换。

    这里模拟一种变换,就是将每一列进行均值位0,方差为1的变换,代码如下:

    import pandas as pd
    import numpy as np
    
    df = pd.read_csv('d:/data.csv')
    
    df_new = df.apply(lambda col: (col - col.mean()) * 1.0 / col.std())
    df_new

    其中,df.apply()函数是df的一个函数式接口,表示依次对df的列(A/B/C)进行迭代,其参数为一个lambda表达式,lambda的参数col就表示df的一个列。

    col其实是Series的一个对象,其中包含大量的数据处理方法,这里实用的是其中两个:均值mean()和std()方差。

    lambda的实现部分使用了Pandas的向量化的运算方式,也就是说col虽然是一个Series,但是我们对其操作就像操作一个标量一样,但是自动传播给所有的元素。

    经过上述代码的运算,每一列都被映射到新的df_new中,这个方式在机器学习、数据挖掘中很常见。结果如下图所示。

     ABC
    0 -0.102247 0.100417 1.865099
    1 0.652462 1.435738 0.944303
    2 -1.060854 -0.839506 0.448149
    3 0.952021 -0.105966 -1.084541
    4 -1.561285 -0.553528 0.542008
    5 -0.344998 -1.358795 -0.884620
    6 -0.086294 0.320234 -1.031713
    7 0.692439 1.341107 0.387790
    8 1.678338 -1.194799 -0.952147
    9 -0.819582 0.855099 -0.234328

    现在,我们要使用df_new的数据计算我们的结果了。如果逻辑很简单,则可以直接通过Pandas的IF THEN逻辑实现,复杂的算法可以需要自己一行一行的遍历df_new,通过if else逻辑实现。我们先说一个简单的情况。

    假如,我们的算法是这样的:如果A>0.5并且B<0.5,则为True,否则如果C>0.5,则为True,则否为False,实现代码如下所示:

    import pandas as pd
    import numpy as np
    
    df = pd.read_csv('d:/data.csv')
    
    df_new = df.apply(lambda col: (col - col.mean()) * 1.0 / col.std())
    
    df_new.ix[(df_new.A > 0.5) & (df_new.B < 0.5), 'Result'] = True
    df_new.ix[~((df_new.A > 0.5) & (df_new.B < 0.5)) & (df_new.C > 0.5), 'Result'] = True
    df_new.ix[~(~((df_new.A > 0.5) & (df_new.B < 0.5)) & (df_new.C > 0.5)), 'Result'] = False
    df_new

    结果如下所示:

    Out[68]:
     ABCResult
    0 -0.102247 0.100417 1.865099 True
    1 0.652462 1.435738 0.944303 True
    2 -1.060854 -0.839506 0.448149 False
    3 0.952021 -0.105966 -1.084541 False
    4 -1.561285 -0.553528 0.542008 True
    5 -0.344998 -1.358795 -0.884620 False
    6 -0.086294 0.320234 -1.031713 False
    7 0.692439 1.341107 0.387790 False
    8 1.678338 -1.194799 -0.952147 False
    9 -0.819582 0.855099 -0.234328 False

    由于算法逻辑不是很复杂,抽象起来也就三个情况,所以通过Pandas的IF Then的机制实现了Result列的添加。

    DataFrame.ix[condition, 'newOrExistsColname'] = value,具体可以参考Pandas的十分钟入门教程,开始就是讲这个的。

    需要强调的是我们通过df_new.A这样的方式访问A列元素,这是Pandas的方便之处;并且各种比较和& ~操作都是针对元素的;并且只有index相同的元素才会比较,而且Result也是添加到对应的index列的。

    假如算法实现在太复杂,不是简单的集中情况可以讲清楚的,这个时候我采用的方法就是C++和Java中最常使用的for循环了,几乎万能。还以上述的算法为例,代码如下:

    import pandas as pd
    import numpy as np
    
    df = pd.read_csv('d:/data.csv')
    
    df_new = df.apply(lambda col: (col - col.mean()) * 1.0 / col.std())
    
    result = pd.Series([False]*len(df_new))
    for i in range(len(df_new)):
        item = df_new.iloc[i, :]
        if item.A > 0.5 and item.B < 0.5:
            result[i] = True
        elif item.C > 0.5:
            result[i] = True
        else:
            result[i] = False # unnecessary
    df_new['Result'] = result
    df_new

    代码中一片浓郁的C、Java风格,虽然不那么函数式也不向量化,但是我就是感觉熟悉,毕竟我最早学习的是C。

    首先,我定义了一个Series,初始化为False,然后通过一个for循环,遍历df_new的所有行,依次为result赋值,最后,通过df_new['newcolname']=的方式将resut追加到df_new中了。

    注意,当将Series往DataFrame或者Series中拼接的时候,默认的都是安装index对齐的,也就是行的index一致的才会拼接到一起,而与行的顺序无关,这点是Pandas的强大之处(数据的自动对齐,在groupby之后的数据中特别有用),千万别忽视了这点。

    最后,我们要将df_new.Result追加给df,因为df_new.Result本质上还是一个Series,所以上述的代码中已经有了一种方式:df.ix['Result']=df_new.Result。

    代码如下:

    import pandas as pd
    import numpy as np
    
    df = pd.read_csv('d:/data.csv')
    
    df_new = df.apply(lambda col: (col - col.mean()) * 1.0 / col.std())
    
    result = pd.Series([False]*len(df_new))
    for i in range(len(df_new)):
        item = df_new.iloc[i, :]
        if item.A > 0.5 and item.B < 0.5:
            result[i] = True
        elif item.C > 0.5:
            result[i] = True
        else:
            result[i] = False # unnecessary
    df_new['Result'] = result
    df['Result'] = df_new.Result
    df

    最终结果如下:

    Out[77]:
     ABCResult
    0 4.556326 4.946749 9.240499 True
    1 6.798123 9.205499 6.495702 True
    2 1.708867 1.949048 5.016719 False
    3 7.687936 4.288530 0.447928 True
    4 0.222381 2.861120 5.296501 True
    5 3.835255 0.292876 1.043872 False
    6 4.603713 5.647815 0.605405 False
    7 6.916871 8.903690 4.836793 False
    8 9.845397 0.815908 0.842583 True
    9 2.425546 7.353661 2.982326 False

    本文要点:

    Pandas读取CSV文件方法;

    Pandas的追加新列方法:df.ix[condition, 'newcolname'] = value(标量或者向量) 或者 df['newcolname'] = value(标量或者向量);

    Pandas的df.apply()对列进行迭代的方法;

    Pandas的df中的一些常用的数据处理方法;

    Pandas的Series的简单逻辑操作& | ~;

    看,是不是很简单。

    未完待续……

  • 相关阅读:
    ORACLE学习-1.过滤和排序
    Java-net.sf.json.JSONException: java.lang.reflect.InvocationTargetException处理方法之一
    ORACLE
    java日常-com.alibaba.fastjson快速处理json字符串转成list类型
    java日常-List、Map初始值
    javaScript中获取时间
    获取select的option值及其文本
    java日常-通过年月,获取到月的第一天和最后一天
    sybase powerdesigner 16.5注册码
    05-Docker私有仓库
  • 原文地址:https://www.cnblogs.com/ledao/p/4545212.html
Copyright © 2011-2022 走看看