干净整洁的数据是后续进行研究和分析的基础。数据科学家们会花费大量的时间来清理数据集,毫不夸张地说,数据清洗会占据他们80%的工作时间,而真正用来分析数据的时间只占到20%左右。
所以,数据清洗到底是在清洗些什么?
通常来说,你所获取到的原始数据不能直接用来分析,因为它们会有各种各样的问题,如包含无效信息,列名不规范、格式不一致,存在重复值,缺失值,异常值等…
拿到一个全新的数据集,我们需要先了解数据,看看它长什么样子。
常用的方法和属性如下:
方法 | 属性 |
---|---|
.head() | 查看前n行数据,默认值是5 |
.tail() | 查看后n行数据,默认值是5 |
.shape | 查看数据维数 |
.columns | 查看所有列名 |
.info() | 查看索引、数据类型和内存信息 |
.describe() | 查看每列数据的基本统计值,包括计数值、均值、标准差、最小最大值、1/4、1/2、3/4分位数。 |
.value_counts() | 查看Series对象的唯一值和计数值 |
了解数据集之后,我们就可以开始对数据集进行清洗了,前面提到通常要处理的问题有包含无效信息,列名不规范、格式不一致,存在重复值,缺失值,异常值等。
在分析一个数据集的时候,很多信息其实是用不到的,因此,需要去除不必要的行或列。这里以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
当原始数据的列名不好理解,或者不够简洁时,可以用.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
数据默认的索引是从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
字符串str操作是非常实用的,因为列中总是会包含不必要的字符,常用的方法如下:
方法 | 属性 |
---|---|
str.lower() | 把大写转换成小写 |
str.upper() | 把小写转换成大写 |
str.capitalize() | 设置首字母大写 |
str.replace() | 替换特定的字符 |
str.strip() | 去除字符串中的头尾空格、以及\n \t |
tr.split(‘x’) | 使用字符串中的’x’字符作为分隔符,将字符串分隔成列表 |
str.get() | 选取列表中某个位置的值 |
str.contains() | 判断是否存在某个字符,返回的是布尔值 |
str.find() | 检测字符串中是否包含子字符串str,如果是,则返回该子字符串开始位置的索引值 |
重复数据会消耗不必要的内存,在处理数据时执行不必要的计算,还会使分析结果出现偏差。因此,我们有必要学习如何删除重复数据。
一个简单的例子代码:
删除缺失值:
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()
这里的数据是我们自己建立的,数据量特别小,当我们遇到大量数据的时候,我们通常需要先执行上面的第一步。
数据集中经常会存在缺失值,学会正确处理它们很重要,因为在计算的时候,有些无法处理缺失值,有些则在默认情况下跳过缺失值。而且,了解缺失的数据,并思考用什么值来填充它们,对做出无偏的数据分析至关重要。
填充缺失值:
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)
需要导入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')
项目描述:
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)
# 导入数据生成器
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)
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