python---数据清洗

干净整洁的数据是后续进行研究和分析的基础。数据科学家们会花费大量的时间来清理数据集,毫不夸张地说,数据清洗会占据他们80%的工作时间,而真正用来分析数据的时间只占到20%左右。

所以,数据清洗到底是在清洗些什么?

通常来说,你所获取到的原始数据不能直接用来分析,因为它们会有各种各样的问题,如包含无效信息,列名不规范、格式不一致,存在重复值,缺失值,异常值等…

1、了解数据

拿到一个全新的数据集,我们需要先了解数据,看看它长什么样子。

常用的方法和属性如下:

方法 属性
.head() 查看前n行数据,默认值是5
.tail() 查看后n行数据,默认值是5
.shape 查看数据维数
.columns 查看所有列名
.info() 查看索引、数据类型和内存信息
.describe() 查看每列数据的基本统计值,包括计数值、均值、标准差、最小最大值、1/4、1/2、3/4分位数。
.value_counts() 查看Series对象的唯一值和计数值

2、清洗数据

了解数据集之后,我们就可以开始对数据集进行清洗了,前面提到通常要处理的问题有包含无效信息,列名不规范、格式不一致,存在重复值,缺失值,异常值等。

1、去除不需要的行、列

在分析一个数据集的时候,很多信息其实是用不到的,因此,需要去除不必要的行或列。这里以csv文件为例,在导入的时候就可以通过设置pd.read_csv()里面的参数来实现这个目的。

【header】默认header=0,即将文件中的0行作为列名和数据的开头,但有时候0行的数据是无关的,我们想跳过0行,让1行作为数据的开头,可以通过将header设置为1来实现。

【usecols】根据列的位置或名字,如[0,1,2]或[‘a’, ‘b’, ‘c’],选出特定的列。

【nrows】要导入的数据行数,在数据量很大、但只想导入其中一部分时使用。

导入数据,只选取前100行和特定几列。

subset_columns = ['Job #', 'Doc #', 'Borough', 'Initial Cost', 'Total Est. Fee']
df = pd.read_csv('文件路径', nrows=100, usecols=subset_columns)
df.head()
Out[15]: 
       Job #  Doc #   Borough Initial Cost Total Est. Fee
0  420291794      1    QUEENS     $2000.00        $100.00
1  420291801      1    QUEENS    $15000.00        $151.50
2  340644128      1  BROOKLYN    $44726.00        $234.00
3  421685439      1    QUEENS        $0.00        $243.00
4  421677974      2    QUEENS   $105000.00       $1275.60

再看一下将header设置为1的效果,但这里其实不需要这么做,因为0行数据是有用的。

df = pd.read_csv('文件路径', nrows=100, header=1)
df.head()
Out[15]: 
0  420291794      1    QUEENS     $2000.00        $100.00
1  420291801      1    QUEENS    $15000.00        $151.50
2  340644128      1  BROOKLYN    $44726.00        $234.00
3  421685439      1    QUEENS        $0.00        $243.00
4  421677974      2    QUEENS   $105000.00       $1275.60

如果在数据导入之后,还想删除某些行和列,可以用 .drop() 方法。

先创建一个列表list,把不需要的列名放进去,再调用.drop() 方法,参数axis为1时代表列,为0时代表行,参数inplace=True表示不创建新的对象,直接对原始对象进行修改。这里我们删除前两列。

to_drop = ['Job #', 'Doc #']
df.drop(to_drop, axis=1, inplace=True)
df.head()
Out[22]: 
    Borough Initial Cost Total Est. Fee
0    QUEENS     $2000.00        $100.00
1    QUEENS    $15000.00        $151.50
2  BROOKLYN    $44726.00        $234.00
3    QUEENS        $0.00        $243.00
4    QUEENS   $105000.00       $1275.60

2、重新命名列

当原始数据的列名不好理解,或者不够简洁时,可以用.rename()方法进行修改。这里我们把英文的列名改成中文,先创建一个字典,把要修改的列名定义好,然后调用rename()方法。

new_names = {'Borough': '区', 'Initial Cost': '初始成本', 'Total Est. Fee': '总附加费用'}
df.rename(columns=new_names, inplace=True)
df.head()
Out[23]: 
          区        初始成本     总附加费用
0    QUEENS    $2000.00   $100.00
1    QUEENS   $15000.00   $151.50
2  BROOKLYN   $44726.00   $234.00
3    QUEENS       $0.00   $243.00
4    QUEENS  $105000.00  $1275.60

3、重新设置索引

数据默认的索引是从0开始的有序整数,但如果想把某一列设置为新的索引,可以用.set_index()方法实现,在示例中我们把"区"这列设置为新索引。

df.set_index('区', inplace=True)
df.head()
Out[24]: 
                初始成本     总附加费用
                             
QUEENS      $2000.00   $100.00
QUEENS     $15000.00   $151.50
BROOKLYN   $44726.00   $234.00
QUEENS         $0.00   $243.00
QUEENS    $105000.00  $1275.60

4、用字符串操作规范列

字符串str操作是非常实用的,因为列中总是会包含不必要的字符,常用的方法如下:

方法 属性
str.lower() 把大写转换成小写
str.upper() 把小写转换成大写
str.capitalize() 设置首字母大写
str.replace() 替换特定的字符
str.strip() 去除字符串中的头尾空格、以及\n \t
tr.split(‘x’) 使用字符串中的’x’字符作为分隔符,将字符串分隔成列表
str.get() 选取列表中某个位置的值
str.contains() 判断是否存在某个字符,返回的是布尔值
str.find() 检测字符串中是否包含子字符串str,如果是,则返回该子字符串开始位置的索引值

5、删除重复数据

重复数据会消耗不必要的内存,在处理数据时执行不必要的计算,还会使分析结果出现偏差。因此,我们有必要学习如何删除重复数据。

一个简单的例子代码:

删除缺失值:

import numpy as np
import pandas as pd

def create_csv():
    """测试删除缺失值的数据准备"""
    # 创建一个带有缺失值的数据
    df = pd.DataFrame(np.arange(12).reshape(3,4),
                      index=['user1','user2','user3'],
                      columns=['views','likes','count','price'])

    # 第2行的第三列为缺失值
    df.iloc[1,2] = np.nan
    # print(df)
    # 将数据存储到csv文件中
    df.to_csv('doc/data-clean.csv')

def drop_null_data():
    # 读取数据
    df = pd.read_csv('doc/data-clean.csv')
    df1 = df.dropna() # 默认删除带有缺失值的那一行
    # df1 = df.dropna(axis=1) # 删除带有缺失值的那一列,不建议使用
    print(df1)

if __name__ == '__main__':
    drop_null_data()

这里的数据是我们自己建立的,数据量特别小,当我们遇到大量数据的时候,我们通常需要先执行上面的第一步。

6、填充缺失值

数据集中经常会存在缺失值,学会正确处理它们很重要,因为在计算的时候,有些无法处理缺失值,有些则在默认情况下跳过缺失值。而且,了解缺失的数据,并思考用什么值来填充它们,对做出无偏的数据分析至关重要。
填充缺失值:

import numpy as np
import pandas as pd

df = pd.DataFrame(np.arange(12).reshape(4,3),
                  index=['user1', 'user2', 'user3', 'user4'],
                  columns=['count', 'views', 'price'])

df.price.iloc[0] = np.nan
df.price.iloc[2] = 5
print('元数据:',df)

# 均值填充缺失值
df_mean = df.price.fillna(df.price.mean())
# price_mean = df.price.mean()
# # df_mean = df['price'].fillna(price_mean)
print(df_mean)
# df.price = df_mean
# print(df)

# 使用中位数进行填充缺失值
df_median = df.price.fillna(df.price.median())
print(df_median)
df.price = df_median
print(df)


# 使用众数进行填充
# 众数返回的是Series对象,需要通过索引获取值
df_mode = df.price.fillna(df.price.mode()[0])
print(df_mode)
# df.price = df_mode
# print(df)

案例:stock股票数据画图

需要导入tushare 和 seaborn模块

查看600848这支股票的数据并画图

from datetime import date
import matplotlib.pyplot as plt
import seaborn as sns
import tushare as ts

def draw_close(code):
    """
    1.近一个月股票收盘价走势图
    2.5日、10日以及20日均线
    3.每日收盘价涨跌幅度,diff(差值)/pct_change(涨/跌幅度百分比)
    :param code:
    :return:
    """
    # 数据准备与样式设置
    sns.set(style='whitegrid')
    plt.rcParams['font.sans-serif'] = ['SimHei']
    end = date.today() # 日期对象
    start = date(end.year, end.month-1, end.day) # 日期对象
    end = str(end)
    start = str(start)
    # 获取股票过去一个月的数据
    df = ts.get_hist_data(code, start, end)
    print(df)

    # 创建子图
    ax1 = plt.subplot(3,1,1)
    # 获取收盘价,绘制子图
    df['close'].plot(label='收盘价')
    df['open'].plot(label='开盘价')
    ax1.set_title('%s股票收盘价/收盘价走势曲线' %(code))
    ax1.legend(loc='upper right')

    # 创建子图
    ax2 = plt.subplot(3, 1, 2)
    ax2.set_title('%s股票均线走势曲线' %(code))
    df['ma5'].plot()
    df['ma10'].plot()
    df['ma20'].plot()
    ax2.legend(loc='upper right')

    # 创建子图
    ax3 = plt.subplot(3,1,3)
    ax3.set_title('%s股票每日涨跌幅度曲线'%(code))
    df['Daily Return'] = df['close'].pct_change()
    df['Daily Return'].plot()
    # ax3.legend(loc='upper right')


    plt.show()
if __name__ == '__main__':
    draw_close('600848')

python---数据清洗_第1张图片

量化股票提醒系统

项目描述:
1、实时获取股票数据
2、连接邮件服务器
3、预警配置管理
4、监控数据并发送邮件
最终通过实时提醒,来提高交易的收益率。结合crontab定时任务,每天9.30开始执行脚本
from datetime import datetime
from time import sleep
import tushare as ts

# 实时获取股票数据
def get_cur_price(code):
    """

    :param code:
    :return:
    """
    #获取实时交易数据 getting real time quotes data
    # 用于跟踪交易情况(本次执行的结果-上一次执行的数据)
    df = ts.get_realtime_quotes(code)
    name, price, high, low, time = df.name[0], float(df.price[0]), float(df.high[0]), float(df.low[0]), df.time[0]
    return name, price, high, low, time

# 2、连接邮件服务器,发送邮件
def send_email(to,title,text):
    """发送邮件"""
    print('收件人: %s 主题: %s 邮件正文: %s'%(to,title,text))

# 3、预警的配置管理
class Setting:
    max_price = 19
    min_price = 18
    send_user = '[email protected]'
    to_user = '[email protected]'
    code = '600848'

# 4、监控数据并发送邮件
while True:
    # 特殊的设置:如果是周六周天或者周内的9:30-15:30除外
    today = datetime.now() #2020-05-02 23:27:36.144166
    weekday = today.weekday() # 0-周一 。。。。5-周六
    trade_start_time = datetime(year=today.year, month=today.month, day=today.day,
                                hour=9, minute=30,second=0)
    trade_end_time = datetime(year=today.year, month=today.month, day=today.day,
                                hour=15, minute=30, second=0)
    #周六周天不交易
    if weekday == 5 or weekday == 6:
        print('[交易停止] 节假日周六周天不交易')
        break
    # 9.30到15.30不交易
    if today < trade_start_time or trade_end_time < today:
        print('[交易停止] 交易时间9:30 - 15:30,当前时间:%s' %(today))
        break

    # 逻辑判断
    name, price, high, low, time = get_cur_price(Setting.code)
    print('>>{} price {}'.format(time, price))
    text_format = '股票{} 价格{} 最高价{} 最低价{}'
    if price < Setting.min_price:
        title = '%s股票下跌提醒' %(name)
        text = text_format.format(name, price, high, low)
        send_email(Setting.to_user, title=title, text=text)

    if price > Setting.max_price:
        title = '%s股票上涨提醒' %(name)
        text = text_format.format(name, price, high, low)
        send_email(Setting.to_user, title=title, text=text)

    sleep(3)

K近邻分类算法

# 导入数据生成器
from sklearn.datasets import make_blobs
from sklearn.neighbors import KNeighborsClassifier
import matplotlib.pyplot as plt

# 生成数据集
# random_state随机种子,保证每次随机生成的样本信息一致
X,y = make_blobs(n_samples=100, n_features=2, centers=2, random_state=8)

# 通过散点图,清楚的看到分为2类
plt.scatter(X[:,0], X[:,1], edgecolors='orange', color='white')
test_data = [6,3] # 测试集:测试模型好坏/正确率的数据集
plt.scatter(test_data[0], test_data[1], marker='*', color='r')
plt.show()

#如何去寻找一个模型,并最终根据模型预判断新的测试数据所属的分类
#机器学习:寻找一个函数/模型的过程
clf = KNeighborsClassifier()
clf.fit(X,y)  # 拟合(寻找模型的过程)

class_name = clf.predict([test_data])
print('新的数据点的分类是:',class_name)

python---数据清洗_第2张图片

K近邻的回归算法

import matplotlib.pyplot as plt
import numpy as np
from sklearn.datasets import make_regression
from sklearn.neighbors import KNeighborsRegressor

# 产生回归的数据集(训练集)
X,y = make_regression(n_samples=100, n_features=1, n_informative=1,
                 noise=50, random_state=8)

# 通过K近邻的回归器,拟合/寻找模型
reg = KNeighborsRegressor()
reg.fit(X, y)

# 给定一些新的数据(测试集),预测y值
"""
np.linspace(-3,3,100)是一维数组
reshape(-1,1)生成n行1列的矩阵
reg.predict()需要的是n*1的数组
"""
test_x = np.linspace(-3,3,100).reshape(-1,1)
test_y = reg.predict(test_x)
print('模型的准确度:',reg.score(X,y))

# 解决中文乱码问题
plt.rcParams['font.sans-serif']=['SimHei']
# 绘制图形
plt.scatter(X,y, marker='*', color='r', edgecolors='orange', label='训练集')
plt.plot(test_x, test_y, color='black', label='测试集')
plt.title('KNN Regressor')
plt.legend()
plt.show()


模型的准确度: 0.7721167832505298

python---数据清洗_第3张图片
参考文档:

  1. https://www.jianshu.com/p/a93fe1423bc5
  2. https://blog.csdn.net/zw0Pi8G5C1x/article/details/84610050

你可能感兴趣的:(数据分析)