美文网首页
数据规整化:清理、转换、合并、重塑

数据规整化:清理、转换、合并、重塑

作者: Shinichi新一君 | 来源:发表于2017-04-28 14:05 被阅读220次

    合并数据集

    pandas对象中的数据可以通过一些内置的方式进行合并:

    pandas.merge根据一个或多个键将不同DataFrame的行连接起来;
    它实现数据库的连接操作

    pandas.concat可以沿着一条轴将多个对象堆叠在一起

    实例方法combine_first可以将重复数据编接在一起,用一个对象中的值填充另一个对象中的缺失值

    数据库风格的DataFrame合并

    pd.merge(df1, df2, on='key') #这里是列名相同,指定'key'列当做键的内连接(对键取交集)
    当两个列名不同时,需要分别指定:
    pd.merge(df3, df4, left_on='key1', right_on='key2')

    如果是左连接\右连接\外连接(取并集),也需要分别指定
    how = 'left'\'right'\'outer'

    要根据多个键进行合并,传入一个由列名组成的列表即可
    on=['key1', 'key2']

    警告:在进行列-列连接时,DataFrame对象中的索引会被丢弃

    重复列名的处理(如何重命名轴标签)
    merge有一个suffixes选项,可以指定附加到左右连个DataFrame对象的重叠列名的字符串
    suffixes =('_left', '_right') #这里就是分别添加字符串到重叠列名后面,可自定义(默认为_x, _y)

    表7-1: merge函数的参数

    索引上的合并

    连接键位于索引中,可以传入left_index=True\right_index=True
    pd.merge(df1, df2, left_on='key', right_index=True)

    对于层次化索引的数据,必须以列表的形式指明用作合并键的多个列(注意对重复索引值的处理)
    pd.merge(lefth,righth,left_on=['key1','key2'],right_index=True)

    DataFrame的join实例方法,能更为方便的实现按索引合并
    left2.join(right2, how='outer')
    对于简单的索引合并,还可以向join传入一组DataFrame(后面会介绍更为通用的concat函数)
    left2.join([right2,another],how='outer')

    轴向连接

    另一种数据合并运算被称作连接(concatenation)\绑定(binding)或堆叠(stacking).
    NumPy有一个用于合并原始NumPy数组的concatenation函数
    np.concatenate([arr,arr],axis=1) #如果没有axis=1,会从上往下拼接\否则从左到右拼接

    对于pandas对象,需要考虑:
    1. 如果各对象其他轴上的索引不同,那些轴应该是做并集还是交集
    2. 结果对象中的分组需要各不相同吗
    3. 用于连接的轴重要

    对于Series:
    pd.concat([s1,s2,s3]) #默认是在axis=0上工作,产生新的Series(从上往下拼接);
    如果传入axis=1,结果变成一个DataFrame;
    默认是外连接,传入join='inner'可得到交集(内连接)
    pd.concat([s1,s4],axis=1,join='inner')
    可以通过join_axes指定要在其他轴上使用的索引
    pd.concat([s1,s4],axis=1,join_axes=[['a','c','b','e']])
    如果想创建层次化索引,将参与连接的片段在结果中区分开,使用keys参数
    result=pd.concat([s1,s1,s3],keys=['one','two','three'])

    同样的逻辑对于DataFrame对象也是一样
    pd.concat([df1,df2],axis=1,keys=['level1','level2'])
    pd.concat({'level1':df1,'level2':df2},axis=1) #这两个表达式效果是一样的

    可以传入ignore_index=True,不保留连接轴上的索引,产生一组新索引range(total_length)

    表7-2: concat函数的参数

    合并重叠数据

    np.where(pd.isnull(a),b,a) #NumPy的where函数,pd.isnull(a)表示判断条件,若为True,返回b\False则返回a
    Series的combine_first方法实现同样功能
    b.combine_first(a) #可以对a\b进行切片;这里表示若b不为空返回b,否则返回a

    对于DataFrame,combine_first也是做同样的事情,可以看做用参数对象(a)中的数据为调用者对象(b)缺失数据'打补丁'
    df1.combine_first(df2)

    重塑和轴向旋转

    有许多用于重新排列表格型数据的基础运算,这些函数成为重塑(reshape)或轴向旋转(pivot)运算

    重塑层次化索引

    层次化索引为DataFrame数据的重排提供一种良好的一致性方式
    1. stack: 将数据的列'转换'为行
    2. unstack: 将数据的行'转换'为列

    如果不是所有的级别值都能在各分组中找到,unstack操作可能引入缺失数据

    stack会默认滤除缺失数据,可以传入dropna=False选择不滤除缺失数据

    将「长格式」旋转为「宽格式」

    pivoted=ldata.pivot('date','item','value')
    前两个参数值分别作为行和列索引的列名,最后一个参数用于填充DataFrame的数据列的列名

    假设有两个需要参与重塑的数据列,如果忽略最后一个参数,得到的DataFrame就会带有层次化的索引

    注意,pivot其实只是一个快捷方式,用set_index创建层次化索引,再用unstack重塑

    数据转换

    过滤、清理以及其他的转换

    移除重复数据

    data.duplicated()
    返回一个布尔型Series,表示各行是否有重复行

    data.drop_duplicates()
    可以传入根据某一列来过滤: data.drop_duplicates(['k1'])
    默认保留第一个出现值组合,传入take_last=True,则保留最后一个

    利用函数或映射进行数据转换

    data=DataFrame({'food':['bacon','pulled pork','bacon','Pastrami','corned beef','Bacon','pastrami','honey ham','nova lox'],'ounces':[4,3,12,6,7.5,8,3,5,6]})

    meat_to_animal={'bacon':'pig','pulled pork':'pig','pastrami':'cow','corned beef':'cow','honey ham':'pig','nova lox':'salmon'}

    data['animal']=data['food'].map(str.lower).map(meat_to_animal)data

    data['food'].map(lambda x:meat_to_animal[x.lower()])

    替换值

    利用fillna方法填充缺失数据可以看做值替换的一种特殊情况

    data=Series([1.,-999.,2.,-999.,-1000.,3.])

    data.replace(-999,np.nan)

    data.replace([-999,-1000],np.nan)
    替换多个值

    data.replace([-999,-1000],[np.nan,0])
    可以是列表形式

    data.replace({-999:np.nan,-1000:0})
    可以是字典形式

    重命名轴索引

    In [9]: data.index.map(str.upper)
    Out[9]: array(['OHIO', 'COLORADO', 'NEW YORK'], dtype=object)
    返回值为array类型
    也可以直接修改data = ***In[9]***

    In [28]: data.rename(index=str.title, columns=str.upper)
    Out[28]:
    ONE  TWO  THREE  FOUR
    Indiana    0    1      2    3
    Colorado    4    5      6    7
    New York    8    9    10    11
    修改columns标签值,返回Dataframe类型

    特别说明,rename可以结合字典型对象实现对部分轴标签的更新
    In [31]: data.rename(index={'INDIANA':'Los Angeles'},columns={'four':'peekaboo'})
    如果想直接修改,可以传入inplace=True

    离散化和面元划分

    为了便于分析,连续数据常常被离散化或拆分为「面元」(bin),比如年龄组的划分.

    ages = [20, 22, 25, 27, 21, 23, 37, 31, 61, 45, 41, 32]
    bins = [18, 25, 35, 60, 100]
    cats = pd.cut(ages, bins)
    cats
    pandas返回一个特殊的Categorical对象,包含不同分类名称的categories数组和一个为年龄数据进行标号的labels属性
    cats.labels
    array([0, 0, 0, 1, 0, 0, 2, 1, 3, 2, 2, 1], dtype=int8)
    In [45]: cats.categories(书中是levels,py3不包含该方法)
    Out[45]: Index(['(18, 25]', '(25, 35]', '(35, 60]', '(60, 100]'], dtype='object')
    In [50]: pd.value_counts(cats)
    Out[50]:
    (18, 25]    5
    (35, 60]    3
    (25, 35]    3
    (60, 100]    1
    dtype: int64

    区间默认是左开右闭,传入right = False表示左闭右开

    可以设置面元名称,将labels选项设置为一个列表或数组即可
    即在cut函数中,传入labels=***列表或元祖***

    pd.cut(data,4,precision=2)
    表示将data计算4个等长面元,precision表示小数点精确度

    qcut可以根据样本分位数对数据进行划分
    也可以设置自定义的分位数,传入0到1的数值列表即可,比如[0, 0.1 ,0.5, 0.9, 1]

    检测和过滤异常值(孤立点或离群值outlier)

    data = DataFrame(np.random.randn(1000, 4))

    col = data[3]
    col[np.abs(col) > 3]
    找出某列中绝对值超过3的值

    data[(np.abs(data)>3).any(1)]
    找出全部绝对值超过3的(存在超过3的数值的行即返回)

    data[np.abs(data)>3]=np.sign(data)*3
    将最大最小值改为3和-3
    其中np.sign返回一个由1和-3组成的数组

    排列和随机采样

    numpy.random.permutation函数可以返回一个新顺序的数组
    比如***permutation***(5)返回的是0,1,2,3,4的随机顺序的数组

    然后就可以基于ix的索引操作或take函数使用该数组对DataFrame进行排序
    df = DataFrame(np.arange(5 * 4).reshape((5, 4)))
    sampler = np.random.permutation(5)
    df.take(sampler)

    选取随机子集
    df.take(np.random.permutation(len(df))[:3])黑体可以用上文的sampler代替

    计算指标/哑变量

    常用于统计建模或机器学习的转换方式:
    分类变量(categorical variable)转换为哑变量矩阵(dummy matrix)指标矩阵(indicator matrix)

    如果DataFrame的某一列中含有k个不同的值,则可以派生出一个k列矩阵或DataFrame,其值全为1或0

    df = DataFrame({'key': ['b', 'b', 'a', 'c', 'a', 'b'],'data1': range(6)})
    pd.get_dummies(df['key'])
    data1这一列没有重复的,将key这一列的所有元素展开到column,0和1为布尔值

    加前缀
    dummies=pd.get_dummies(df['key'],prefix='key')
    df_with_dummy=df[['data1']].join(dummies)
    df_with_dummy

    将get_dummies和诸如cut之类的离散化结合起来使用
    values=np.random.rand(10)
    values
    bins=[0,0.2,0.4,0.6,0.8,1]
    pd.get_dummies(pd.cut(values,bins))

    (0, 0.2]  (0.2, 0.4]  (0.4, 0.6]  (0.6, 0.8]  (0.8, 1]

    0        0          0          0          0        1

    1        0          1          0          0        0

    2        1          0          0          0        0

    3        0          1          0          0        0

    4        0          0          1          0        0

    5        0          0          1          0        0

    6        0          0          0          0        1

    7        0          0          0          1        0

    8        0          0          0          1        0

    9        0          0          0          1        0

    返回的结果为某一栏在第几个Categorial array中出现

    字符串操作

    字符串对象方法

    表7-3
    包含count\join等等

    正则表达式

    pandas中矢量化的字符串函数

    清理散乱数据时,需要做一些字符串的规整化工作(比如处理缺失数据)
    data.map,所有字符串和正则表达式方法能被用于各个值(传入lambda表达式或其他函数),但是遇到NA就回报错;
    Series的str属性可以访问这些方法跳过NA值

    data.str.contains('gmail') 返回布尔值True False

    有两个办法可以实现矢量化的元素获取操作:str.get或者str属性上使用索引

    示例: USDA食品数据库

    相关文章

      网友评论

          本文标题:数据规整化:清理、转换、合并、重塑

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