数据分析2 - 数据导入及处理

数据存在的形式

  • 文件:csv, excel, txt……
  • 数据库:mysql, access, sql server……

导入 CSV 文件

pandas 包中的 read_csv 函数:read_csv(file, encoding)

pandas.read_csv参数整理

from pandas import read_csv

# 相对地址
df = read_csv(
            r'1.csv'
        )
df = read_csv(
            './1.csv'
        )
# 绝对地址
df = read_csv(
            r'C:\Users\lian\Desktop\python\4.1\1.csv'
        )
df = read_csv(
            'C:/Users/lian/Desktop/python/4.1/1.csv'
        )

导入文本文件

pandas 包中的 read_table 函数:read_table(file,names=[列名1,列名2,...],sep="",encoding,...)

参数 注释
names 指定列名,默认以文件中第一行为列名
sep 分隔符,默认为空,表示默认导入为一列。当文本中以,隔开哥哥元素时,需指定为,
from pandas import read_table

df = read_table(
            '2.txt',
            names=['age', 'names'],
            sep=','
        )

当导入中文时存在问题的时候,可以设置 engine = 'python' 解决问题

df = read_table(
            '2.txt',
            names=['age', 'names'],
            sep=',',
            encoding='UTF-8',
            engine='python'
        )

导入 Excel 文件

pandas 包中的 read_excel 函数:read_excel(file,sheetname,names)

参数 注释
sheetname 读取哪一个 sheet
names 指定列名,默认以文件中第一行为列名
from pandas import read_excel

df = read_excel(
            '3.xlsx',
            sheetname='data'
        )

dataFrame 导出为 csv 文件

to_csv 函数:dataFrame.to_csv(file,sep="",index,header)

参数 注释
index 是否导出行序号,默认为 True。实际一般设置为 False
header 是否导出列名,默认为 True
from pandas import DataFrame

df = DataFrame({
            'age':[21,22,23],
            'name':['ken','john','jimi']
        })
# 导出到当前目录下名为 test.csv 的文件
df.to_csv(
            'test.csv',
            index=False
        )

重复值处理

把 dataFrame 中,行相同的数据只保留一行

相关函数:

  • dataFrame.duplicated() 找出或只按指定列找出重复的行,根据是否重复返回元素值为 boolean 的 Series,表示是否重复(重复为 True)
  • dataFrame.drop_duplicates() 删除或值考虑某一列的值删除重复的行,返回新的 DataFrame
from pandas import read_csv

# 导入数据
df = read_csv('data.csv')

# 找出行重复的位置。返回一个 Series,值为 boolean ,表示每行是否重复,当行所有元素的值都重复时,返回 True
dIndex = df.duplicated()

# 根据某些列,找出重复的位置
dIndex = df.duplicated('id')
# 当指定多列时,是 and 关系,即所有指定列都重复了才为 True
dIndex = df.duplicated(['id', 'key'])

#根据返回值,把重复数据提取出来
df[dIndex]

#直接删除重复值
#默认根据所有的列,进行删除
newDF = df.drop_duplicates()
#当然也可以指定某一列,进行重复值处理
newDF = df.drop_duplicates('id')

缺失值的处理

缺失值的处理方式:1. 数据补齐;2. 删除对应缺失行;3. 不处理

相关函数:

  • dataFrame.isnull()
  • dataFrame.any(axis=1)
  • dataFrame.fillna('填充 nan 的值')
  • dataFrame.dropna()
from pandas import read_csv

# 导出数据
# data.csv 本身已有缺失值
df = read_csv(
    'data.csv'
)

# data2.csv 无缺失值,na_values=['a','b'] 表示将元素值为 a 或 b 的元素值设置为 nan
df = read_csv(
    'data2.csv',
    na_values=['a','b']
)

# 找出空值的位置
# isnull() 函数返回一个同结构的 DataFrame(大小、列名、索引相同),但元素值以是否为 null ( nan ) 设置为 boolean 值
isNA = df.isnull()

# 获取出空值所在的行
# isNA.any(axis=1) 返回一个 boolean 值的 Series ,当 axis=1 时表示 isNA 的每一行是否有存在值为 True 的元素,只要有则对应的 boolean 为 True 
# 再根据 dataFrame[series] 过滤出有空值的行
df[isNA.any(axis=1)]

# 获取根据某一列或多列中存在空值所在的行
# isNA[['key']] 得到的是 DataFrame,isNA['key'] 得到的是 Series
df[isNA[['key']].any(axis=1)]

# 获取 key 或 value 列中空值所在的行
df[isNA[['key', 'value']].any(axis=1)]

# 将 df 中元素值为 nan 的值设置为 '未知'
df.fillna('未知')

# 直接删除空值。将有空值的该行删除
newDF = df.dropna()

空格值的处理

相关函数:

  • str.strip() 清除字符型数据左右的空格(lstrip() 清除左边,rstrip() 清除右边)
  • series.str.xxx 表示对 series 中所有字符元素做处理
from pandas import read_csv

df = read_csv(
    'data.csv'
)

# 处理 name 字段中元素的字符
newName = df['name'].str.lstrip()
newName = df['name'].str.rstrip()
newName = df['name'].str.strip()

df['name'] = newName

字段抽取

字段抽取是根据指定字段下的一组数据的开始和结束位置,抽取形成新的列

相关函数:

  • series.astype(str) 对 series 中所有元素转化为 str 类型
  • str.slice(0, 3) 对 str 做切片

字段截取函数:slice(start, stop)

from pandas import read_csv

df = read_csv(
    'data.csv'
)

# 将 df 数据框中 tel 字段的元素值的类型转化为 str 类型,并赋值回去
df['tel'] = df['tel'].astype(str)

#运营商
bands = df['tel'].str.slice(0, 3)
#地区
areas = df['tel'].str.slice(3, 7)
#号码段
nums = df['tel'].str.slice(7, 11)

#赋值回去
df['bands'] = bands
df['areas'] = areas
df['nums'] = nums

字段拆分

字段拆分指按照固定的字符,拆分已有字符串

相关函数:

  • str.split(sep, n, expand)
参数 注释
sep 分割的字符串所用的子字符串
n 分割为多少列。当为 1 时,分割为两列,即只分割找到的第一个 sep
expand 是否展开为数据框,默认 False。当为 True 返回 DataFrame,当为 False 返回 Series
from pandas import read_csv

df = read_csv(
    'data.csv'
)

newDF = df['name'].str.split(' ', 1, True)

newSe = df['name'].str.split(' ', 2, True)

# 默认分割后的列名为 0,1,...
newDF.columns = ['band', 'name']

记录抽取

记录抽取指根据一定的条件,对数据进行抽取

相关函数:
dataFrame[condition] condition 为一 Series,元素数量与 dataFrame 行数相等,元素为 boolean 值,决定是否抽取记录

常用的条件类型:

  • 比较运算
    > < >= <= !=
  • 范围运算
    between(left, right)
  • 空值匹配
    pandas.isnull(column)
  • 字符匹配
    str.contains(pattern, na=False)
  • 逻辑运算
    & | not
    df[(df.comments >= 1000) & (df.comments <= 10000)] 等价于 df[df.comments.between(1000, 10000)]
import pandas

df = pandas.read_csv(
    'data.csv', sep="|"
)

#单条件
df[df.comments>10000]

#多条件
df[df.comments.between(1000, 10000)]

#过滤空值所在行
df[pandas.isnull(df.title)]

#根据关键字过滤
df[df.title.str.contains('台电', na=False)]

#~为取反
df[~df.title.str.contains('台电', na=False)]

#组合逻辑条件
df[(df.comments>=1000) & (df.comments<=10000)]

随机抽样

随机抽样指随机从数据中,按照一定的函数或者比例抽取数据

相关函数:
numpy.random.seed(seed=2) 设置随机种子
dataFrame.sample(n, frac, replace=False)

参数 注释
n 按个数抽样
frac 按百分比抽样
replace 是否可放回抽样。默认 False 不可放回
import numpy
import pandas

data = pandas.read_csv(
    'data.csv'
)


#设置随机种子
numpy.random.seed(seed=2)


#按照个数抽样
data.sample(n=10)
#按照百分比抽样
data.sample(frac=0.02)
#是否可放回抽样
data.sample(n=10, replace=True)

典型抽样 之 分层抽样:

按照某一字段将 dataFrame 分为几组,并在每个分组抽取样本

相关函数:

  • dataFrame.groupby('class', group_keys) 根据对应的字段的值将 dataFrame 分组,从而获取 DataFrameGroupBy 实例。group_keys 指当 DataFrameGroupBy 实例调用 .apply() 函数时,是否添加分组字段的值到索引以便区分。DataFrameGroupBy 实例有属性:
    • dataFrameGroupBy.groups 获取一个 dict,该 dict 以原 dataFrame 所指定 groupby 的字段的值为 key ,value 为对应值的行的索引的集合
    • dataFrameGroupBy.apply(funcName,...) 将分组后的每个 dataFrame 传入指定的函数作处理,该函数定义类似为 def funcName(dataFrame, *args, **kv) ,参数dataFrame 指传进的 dataFrame ,该 dataFrame 与一般 dataFrame 多了一个属性 .name ,指分组对应的字段的值,函数返回一个同参数一样结构的dataFrame。apply() 函数最终返回一个 DataFrame,作为各个分组应用处理后的 dataFrame 的重新整合
# 按 class 列进行分组,得到一个分组对象
gbr = data.groupby("class")
# 获取所有分组字典 
gbr.groups

# 定义一个字典,指明每组需要抽取的个数
typicalNDict = {
    1: 2, 
    2: 4, 
    3: 6
}

# 定义分层抽样的方法
def typicalSampling(group, typicalNDict):
    name = group.name
    n = typicalNDict[name]
    return group.sample(n=n)

# 使用分组对象的 apply 方法
result = data.groupby(
    'class', group_keys=False
).apply(typicalSampling, typicalNDict)

# ==================================================
# 按百分比的方式
typicalFracDict = {
    1: 0.2, 
    2: 0.4, 
    3: 0.6
}

def typicalSampling(group, typicalFracDict):
    name = group.name
    frac = typicalFracDict[name]
    return group.sample(frac=frac)

result = data.groupby(
    'class', group_keys=False
).apply(typicalSampling, typicalFracDict)

记录合并 —— 数据框的合并

记录合并指将两个以上结构相同或不同的数据框,合并成一个数据框

相关函数:

  • concat([df1, df2,...]) 指记录的合并,即假设 df1 有m条记录,df2 有n条记录,则合并后有 m+n 条记录,索引为原来的索引,对于不同 DataFrame 字段不同的问题,则缺失的字段的值以 nan 填充
import pandas
from pandas import read_csv

data1 = read_csv(
    'data1.csv', sep="|"
)
data2 = read_csv(
    'data2.csv', sep="|"
)
data3 = read_csv(
    'data3.csv', sep="|"
)
data = pandas.concat([data1, data2, data3])

# 当列名不一样时,合并后数据缺失部分填充为 nan
data = pandas.concat([
    data1[[0, 1]], 
    data2[[1, 2]], 
    data3[[0, 2]]
])

字段合并 —— 列的合并

字段合并指将同意数据框中的不同列进行合并,形成新的列

字段合并方法:x = x1 + x2 + ... (x 指数据列,Series)

相关函数:

  • dataFrame.astype(str) 将整个 dataFrame 元素的值的类型转化为 str
from pandas import read_csv

df = read_csv(
    'data.csv', 
    sep=" ", 
    names=['band', 'area', 'num']
)

df = df.astype(str)

tel = df['band'] + df['area'] + df['num']

df['tel'] = tel

字段匹配

字段匹配指根据各表共有的关键字段,把各表所需的记录一一对应起来。即把两个 dataFrame 关联起来

相关函数:

  • merge(x,y,left_on,right_on)
参数 注释
x 第一个数据框
y 第二个数据框
left_on 第一个数据框用于匹配的列
right_on 第二个数据框用于匹配的列
how merge 方式
import pandas

items = pandas.read_csv(
    'data1.csv', 
    sep='|', 
    names=['id', 'comments', 'title']
)

prices = pandas.read_csv(
    'data2.csv', 
    sep='|', 
    names=['id', 'oldPrice', 'nowPrice']
)

# 默认只是保留连接得上的部分
# 类似数据库操作的 inner join
itemPrices = pandas.merge(
    items, 
    prices, 
    left_on='id', 
    right_on='id'
)

# 即使连接不上,也保留左边没连上的部分
# 类似数据库操作的 left join
itemPrices = pandas.merge(
    items, 
    prices, 
    left_on='id', 
    right_on='id',
    how='left'
)

# 即使连接不上,也保留右边没连上的部分
# 类似数据库操作的 right join
itemPrices = pandas.merge(
    items, 
    prices, 
    left_on='id', 
    right_on='id',
    how='right'
)

# 即使连接不上,也保留所有没连上的部分
# 类似数据库操作的 full join
itemPrices = pandas.merge(
    items, 
    prices, 
    left_on='id', 
    right_on='id',
    how='outer'
)

简单计算

简单计算指通过对已有字段进行加减乘除等运算,得出新的字段

import pandas

data = pandas.read_csv(
    'data.csv', 
    sep="|"
)

data['total'] = data.price*data.num

#注意,用点的方式,虽然可以访问,但是并没有组合进数据框中
data = pandas.read_csv(
    'data.csv', 
    sep="|"
)

data.total = data.price*data.num

# 错误,因为 data 没有对应的字段 total
data.total

数据标准化

数据标准化指将数据按比例缩放,使之落入到特定区间

0-1 标准化计算

相关函数:

  • series.min()
  • series.max()
  • series.describe() 返回一个 Series ,索引为 count / mean / std / min / 25% / 50% / 75% / max,保存着对应的值
import pandas

data = pandas.read_csv(
    'data.csv'
)

# round 取小数点后两位
data['scale'] = round(
    (
        data.score-data.score.min()
    )/(
        data.score.max()-data.score.min()
    )
    , 2
)

数组分组

数组分组指根据数据分析对象的特征,按照一定的数值指标,把数据分析对象划分为不通的区间进行研究,以揭示其内在的联系和规律性

主要针对如年龄这个字段,值比较分散,我们可以将其划分为如 [ '20以下', '20到40', '40到60', '60到80', '80到100', '100以上' ] ,以便做进一步的分析

相关函数:

  • pandas.cut(series, bins, right=True, labels=NULL) 返回一个 Series
参数 注释
series 需要分组的数据
bins 分组的划分数组
right 分组的时候,右边是否闭合,默认 True。即如 (0, 10] 还是 [0, 10)
labels 分组的自定义标签,可以不自定义
import pandas

data = pandas.read_csv(
    'data.csv', 
    sep='|'
)

# 定义一个分组区间
bins = [
    min(data.cost)-1, 20, 40, 60, 
    80, 100, max(data.cost)+1
]

data['cut'] = pandas.cut(
    data.cost, 
    bins
)

data['cut'] = pandas.cut(
    data.cost, 
    bins, 
    right=False
)

labels = [
    '20以下', '20到40', '40到60', 
    '60到80', '80到100', '100以上'
]

data['cut'] = pandas.cut(
    data.cost, bins, 
    right=False, labels=labels
)

时间处理

时间转换,str => datetime

时间转换函数:

  • pandas.to_datetime(datetimeData, format) 当 datetimeData 为 str 时,返回一个 datetime,当为 series 时,返回一个 series
  • pandas.datetime.strptime(dates, '%Y%m%d')
属性 注释
%Y 年份
%m 月份
%d 日期
%H 小时
%M 分钟
%S 秒钟

时间格式化,datetime => str

  • series.dt 表示对 series 所有 datatime 类型的元素做处理
  • dateTimeStr = datetime.strftime(format) 时间格式化函数

时间属性抽取,指从日期格式里面,抽取出需要的部分属性

时间属性抽取语法:datetime.property

property 可选项 注释
second
minute
hour
day
month
year
weekday
import pandas

data = pandas.read_csv(
    'data.csv', 
    encoding='utf8'
)

data['时间'] = pandas.to_datetime(
    data.注册时间, 
    format='%Y/%m/%d'
)

data['格式化时间'] = data.时间.dt.strftime('%Y-%m-%d')

data['时间.年'] = data['时间'].dt.year
data['时间.月'] = data['时间'].dt.month
data['时间.周'] = data['时间'].dt.weekday
data['时间.日'] = data['时间'].dt.day
data['时间.时'] = data['时间'].dt.hour
data['时间.分'] = data['时间'].dt.minute
data['时间.秒'] = data['时间'].dt.second

时间抽取

时间抽取指按一定条件,对时间格式的数据进行抽取

相关函数:

  • 根据索引进行抽取
    • dataFrame.ix 是 dataFrame 关于 index 的相关操作
    • dataFrame.ix[start: end] 表示获取 index 区间的行
    • dataFrame.ix[dates] 表示获取指定 list 的行
  • 根据时间列进行抽取
    • dataFrame[condition]
import pandas

data = pandas.read_csv(
    'data.csv', 
    encoding='utf8'
)

# 时间相关处理函数,str ==> datetime
dateparse = lambda dates: pandas.datetime.strptime(dates, '%Y%m%d')

# parse_dates 指定需要进行时间处理的字段,date_parser 指定时间处理函数,index_col 所指定的列作为索引
data = pandas.read_csv(
    'data.csv', 
    encoding='utf8',
    parse_dates=['date'],
    date_parser=dateparse,
    index_col='date'
)
#根据索引进行抽取
import datetime

# 创建两个 datatime 类型实例
dt1 = datetime.date(year=2016,month=2,day=1);
dt2 = datetime.date(year=2016,month=2,day=5);

# 切片
data.ix[dt1: dt2]
# list ,指定要获取的 index
data.ix[[dt1,dt2]]
#根据时间列进行抽取
data = pandas.read_csv(
    'data.csv', 
    encoding='utf8',
    parse_dates=['date'],
    date_parser=dateparse,
)

data[(data.date>=dt1) & (data.date<=dt2)]

虚拟变量

虚拟变量,也叫哑变量和离散特征编码,可用来表示分类变量、非数量因素可能产生的影响

虚拟变量的取值有两种:

  1. 离散特征的取值之间有大小的意义,如尺寸(L XL S);
  2. 离散特征的取值之间没有大小的意义,如颜色(红 蓝 绿)

离散特征的取值之间有大小的意义的处理函数:pandas.Series.map(dict)series.map(dict) dict 以 series 的值为 key ,以要映射的值为 value,返回一个 Series

离散特征的取值之间没有大小的意义的处理函数:pandas.get_dummies(data, prefix=None, prefix_sep='_'. dummy_na=False, columns=None, drop_first=False)

属性 注释
data 要处理的 DataFrame
prefix 列名的前缀,在多个列有相同的离散项时使用
prefix_sep 前缀和离散值的分隔符,默认为下划线
dummy_na 是否把 nan 值作为一个离散值进行处理,默认不处理
columns 要处理的列名,如果不指定,则默认处理所有列
drop_first 是否从备选项中删除第一个,建模的时候为避免共线性使用
import pandas

data = pandas.read_csv(
    'data.csv', 
    encoding='utf8'
)

# 可以看出 Education Level 取值之间有大小的意义,我们可以将之与具体的数值映射
data['Education Level'].drop_duplicates()
"""
博士后    Post-Doc
博士      Doctorate
硕士      Master's Degree
学士      Bachelor's Degree
副学士    Associate's Degree
专业院校  Some College
职业学校  Trade School
高中      High School
小学      Grade School
"""

educationLevelDict = {
    'Post-Doc': 9,
    'Doctorate': 8,
    'Master\'s Degree': 7,
    'Bachelor\'s Degree': 6,
    'Associate\'s Degree': 5,
    'Some College': 4,
    'Trade School': 3,
    'High School': 2,
    'Grade School': 1
}

data['Education Level Map'] = data[
    'Education Level'
].map(
    educationLevelDict
)

# 可以看出 Gender 取值之间没有大小的意义
data['Gender'].drop_duplicates()
"""
男    Male
女      Female
空值      nan
"""

# 这里离散值有 Male Female(忽略 nan),加上前缀和分隔符,生成两列 'Gender_Male' 、'Gender_Female' ,以 0或1 表示在原列中是否有对应的值,返回的 dataFrame 不包含原 'Gender' 
dummies = pandas.get_dummies(
    data, 
    columns=['Gender'],
    prefix=['Gender'],
    prefix_sep="_",
    dummy_na=False,
    drop_first=False
)

dummies['Gender'] = data['Gender']
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,547评论 6 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,399评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,428评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,599评论 1 274
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,612评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,577评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,941评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,603评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,852评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,605评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,693评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,375评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,955评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,936评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,172评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,970评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,414评论 2 342

推荐阅读更多精彩内容