美文网首页
day80-数据清洗及数据库连接

day80-数据清洗及数据库连接

作者: barriers | 来源:发表于2019-03-08 20:26 被阅读0次

    1数据清洗

    1.1缺失数据处理

    isnull检测缺失值;dropna删除缺失值;python内置的none值在对象数组中也可以作为na值

    string_data = pd.Series(['aardvark', 'artichoke', np.nan, 'avocado'])
    string_data.isnull()  # 检测空值
    data.dropna()  # 删除空值
    data[data.notnull()]  # 提取出不是空值的数据
    

    DataFrame对象,dropna默认丢弃任何含有缺失值的行(只要有na就删除);传入how=‘all’将只丢弃全为NA的那些行

    cleaned = data.dropna()
    data.dropna(how='all') 
    data.dropna(axis=1, how='all') #删除列上全为空的列
    
    df.iloc[:4, 1] = NA #将1-4行,第2列的数据全置为na
    df.dropna(thresh=2) # 删除大于等于2个非空值的行
    

    1.2缺失数据填充

    填充缺失数据中fillna方法是主要的函数。通过一个常数调用fillna就会将缺失值替换为那个常数值。通过字典调用,可以实现对不同的列填充不同的值

    df.fillna(0) # 将na值填充为0
    df.fillna({1: 0.5, 2: 0})  # 第2列缺失填0.5,第三列缺失填0
    

    fillna默认会返回新对象,但也可以对现有对象进行就地修改

    _ = df.fillna(0, inplace=True)
    

    对reindexing有效的那些插值方法也可用于fillna(如轴标签loc和整数索引iloc及前向填充等)

    df.fillna(method='ffill') #对na值用前向填充
    df.fillna(method='ffill', limit=2)  # 最多前向填充两个
    

    填充series的平均值或中位数

    data = pd.Series([1., NA, 3.5, NA, 7])
    data.fillna(data.mean())  # 有值就用原值,没有就用有数据的平均数
    

    1.3删除重复数据

    data = pd.DataFrame({'k1': ['one', 'two'] * 3 + ['two'],  'k2': [1, 1, 2, 3, 3, 4, 4]})
    data.duplicated()  # 前向比较,与前项相同就标为true
    data.drop_duplicates()  # 删除与前项相同的数据
    data.drop_duplicates(['k1'])  # 根据k1列过滤重复项
    data.drop_duplicates(['k1', 'k2'], keep='last') 
    

    drop_duplicates方法,它会返回一个DataFrame,重复的数组会标为False;duplicated和drop_duplicates默认保留的是第一个出现的值组合。传入keep=‘last’则保留 后一个

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

    根据数组、Series或DataFrame列中的值来实现转换工作

    data = pd.DataFrame({'food': ['bacon', 'pulled pork'], 'ounces': [4, 3,]})
    

    添加一列表示该肉类食物来源的动物类型。我们先编写一个不同肉类到动物的映射

    meat_to_animal = {  'bacon': 'pig',  'pulled pork': 'pig'}
    lowercased = data['food'].str.lower() # 使用Series的str.lower方法;字母转小写
    data['animal'] = lowercased.map(meat_to_animal) # 映射
    

    也可以传入一个能够完成全部这些工作的函数

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

    1.5替换

    -999这个值可能是一个表示缺失数据的标记值。要将其替换为pandas能够理解的NA值(使用replace)

    data = pd.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})  # 也是替换两种数据
    

    1.6重命名轴索引

    transform = lambda x: x[:4].upper() # 将行的索引切前四个并全部大写
    data.index.map(transform)  # 替换行的索引
    

    如果想要创建数据集的转换版(而不是修改原始数据)

    data.rename(index=str.title, columns=str.upper) 
    

    rename可以结合字典型对象实现对部分轴标签的更新;或者就地修改某个数据集,传入inplace=True即可

    # 将OHIO换成INDIANA。three换成peekaboo
    data.rename(index={'OHIO': 'INDIANA'},  columns={'three': 'peekaboo'}) 
    data.rename(index={'OHIO': 'INDIANA'}, inplace=True) # 修改OHIO为INDIANA
    

    1.7离散化和面元划分

    为了便于分析,连续数据常被离散化或拆分为“面元”(bin)。
    分隔后的参数默认为前开后闭,可以对cut进行设置right=False使其前闭后开

    ages = [20, 22, 25, 27, 21, 23, 37, 31, 61, 45, 41, 32]  #年龄表
    bins = [18, 25, 35, 60, 100] # 年龄段划分的断点
    cats = pd.cut(ages, bins) # 划分年龄,返回的是年龄对应的每个年龄段
    pd.value_counts(cats)  # 统计每个区间的人的个数
    pd.cut(ages, [18, 26, 36, 61, 100], right=False)  # 切割成前闭后开的类型
    
    group_names = ['Youth', 'YoungAdult', 'MiddleAged', 'Senior']
    pd.cut(ages, bins, labels=group_names)  # 给每个区间设置名称
    

    向cut传入的是面元的数量而不是确切的面元边界,则它会根据数据的最小值和最大值计算等长面元。下面这个例子中,我们将一些均匀分布的数据分成四组,选项precision=2,限定小数只有两位。
    qcut是一个非常类似于cut的函数,它可以根据样本分位数对数据进行面元划分。

    pd.cut(data, 4, precision=2) 
    cats = pd.qcut(data, 4)
    pd.value_counts(cats)  # 统计个数
    

    cut和qcut区别:cut是将区间进行均分,区间间隔相同,每个区间的数值个数不同 ;qcut是将每个区间的数值进行均分的数值处划分;区间间隔不同,每个区间的数值个数相同。

    1.8检测和过滤异常值

    describe() 统计每一列的个数,平均值,中位数,最大、最小值等;np.sign(data)可以生成1和-1

    data = pd.DataFrame(np.random.randn(1000, 4))
    data.describe()  # 统计每一列的个数,平均值,中位数,最大、最小值等
    
    col = data[2] # 取出第三列
    col[np.abs(col) > 3]  # 统计这列中绝对值大于3的数
    data[(np.abs(data) > 3).any(1)]  # 选出全部含有超过-3或3的行
    np.sign(data).head()  #生成1和-1
    

    1.9排列和随机采样

    利用numpy.random.permutation函数可以轻松实现对Series或DataFrame的列的排列工作 (permuting,随机重排序)

    df = pd.DataFrame(np.arange(20).reshape((5, 4)))
    sampler = np.random.permutation(5)
    df.take(sampler)  # 按随机生成的sampler中的顺序对df进行重排序
    df.sample(n=3)  # 随机排列3行(从df中随机取3行)
    

    要通过替换的方式产生样本(允许重复选择),可以传递replace=True到sample

    choices = pd.Series([5, 7, -1, 6, 4])
    draws = choices.sample(n=10, replace=True)
    

    1.10计算指标

    df = pd.DataFrame({'key': ['b', 'b', 'a', 'c', 'a', 'b'],'data1': range(6)})
    pd.get_dummies(df['key']) # 取key列的数据,并将其作为列的索引,统计每一行出现的位置
    dummies = pd.get_dummies(df['key'], prefix='key') # 统计并给索引加前缀key_
    

    1.11从dat文件中读数据并写入数据库

    在读取数据前,需要退出ipython环境,并运行conda install pymysql安装依赖库

    # 连接数据库
    db= sqla.create_engine('mysql+pymysql://root:123456@127.0.0.1/pdmovie?charset=utf8')
    # 给读取的数据前索引,必须于数据库中的字段保持一致
    mnames = ['movie_id', 'title', 'genres']    
    # 读取数据
    movies = pd.read_table('datasets/movielens/movies.dat', sep='::', header=None, 
        names=mnames, engine='python')
    # 吸入数据库
    movies.to_sql('movies', db,index=False, if_exists='append')
    
    all_genres = []
    # 遍历读取的数据中的genres列,实质上就是一个serise
    for x in movies.genres:
        all_genres.extend(x.split('|'))
    # 对切割后的电影类型去重
    genres = pd.unique(all_genres)
    

    构建指标DataFrame的方法之一是从一个全零DataFrame开始

    zero_matrix = np.zeros((len(movies), len(genres)))
    dummies = pd.DataFrame(zero_matrix, columns=genres)
    

    通过data.map,所有字符串和正则表达式方法都能被应用于(传入lambda表达式或其他函数)各个值,但是如果存在NA(null)就会报错。为了了解决这个问题,Series有一些能够跳过 NA值的面向数组方法,进行字符串操作。通过Series的str属性即可访问这些方法。例如,我们可以通过str.contains检查各个电子邮件地址是否含有"gmail"

    data = {'Dave': 'dave@google.com', 'Steve': 'steve@gmail.com', 'Rob': 'rob@gmail.com', 'Wes': np.nan}
    data = pd.Series(data)
    data.str.contains('gmail')  # 查看是否含有gmail
    

    矢量化字符串函数也可以使用正则表达式,还可以加上任意re选项(如IGNORECASE)

    import re 
    pattern = r'([A-Z0-9._%+-]+)@([A-Z0-9.-]+)\.([A-Z]{2,4})' 
    data.str.findall(pattern, flags=re.IGNORECASE)  # 按@和.符号将其切分为三个部分
    matches = data.str.match(pattern, flags=re.IGNORECASE) # 使用match进行比对
    data.str[:5]  # 对data中的每个字符串进行切片
    

    相关文章

      网友评论

          本文标题:day80-数据清洗及数据库连接

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