Python数据分析(四)

Python数据分析(四)

打卡第八天啦!!!

pandas库(四)

数据加载、存储与文件格式

读写文本格式文件
  1. 直接使用read_csv方法进行读取
df = pd.read_csv('ex.csv')
  1. 使用read_table方法进行读取,需要指定分隔符
pd.read_table('ex.csv',sep=',')
  1. 在读取时可以加上列名,可以使用默认列名或自定义列名
pd.read_csv('ex2.csv',header=None) # 使用默认列名
pd.read_csv('ex2.csv',names=['a','b','c','d','message']) # 使用自定义列名
  1. 指定index_col属性,将某一列作为索引列
df1 = pd.read_csv('ex2.csv',names=['a','b','c','d','message'],index_col='message') # 将message列作为索引列
print(df1)
#          a   b   c   d
# message               
# hello    1   2   3   4
# world    5   6   7   8
# python   9  10  11  12
  1. 指定index_col参数,将多列作为索引列(效果为修改为层次索引)
pa = pd.read_csv('ex3.csv',index_col=['key1','key2'])
print(pa)
#            value1  value2
# key1 key2                
# one  a          1       2
#      b          3       4
#      c          5       6
#      d          7       8
# two  a          9      10
#      b         11      12
#      c         13      14
#      d         15      16
  1. 读取txt文本文件,需要指定sep参数,不指定默认分隔符是\t,不能处理换行符
df2 = pd.read_table('ex4.txt',sep='\s+')
  1. 将数据写入csv文件
df3.to_csv('ex_out.csv')
  1. json数据与Python格式数据的相互转换
# json数据
obj = """
{
  "paramz": {
    "feeds": [
      {
        "id": 299076,
        "oid": 288340,
        "category": "article",
        "data": {
          "subject": "荔枝新闻3.0:不止是阅读",
          "summary": "江苏广电旗下资讯类手机应用“荔枝新闻”于近期推出全新升级换代的3.0版。",
          "cover": "/Attachs/Article/288340/3e8e2c397c70469f8845fad73aa38165_padmini.JPG",
          "pic": "",
          "format": "txt",
          "changed": "2015-09-22 16:01:41"
        }
      }
    ],
    "PageIndex": 1,
    "PageSize": 20,
    "TotalCount": 53521,
    "TotalPage": 2677
  }
}
"""
# 将json字符串转换为Python形式
import json
res = json.loads(obj)
res
# {'paramz': {'feeds': [{'id': 299076,
#     'oid': 288340,
#     'category': 'article',
#     'data': {'subject': '荔枝新闻3.0:不止是阅读',
#      'summary': '江苏广电旗下资讯类手机应用“荔枝新闻”于近期推出全新升级换代的3.0版。',
#      'cover': '/Attachs/Article/288340/3e8e2c397c70469f8845fad73aa38165_padmini.JPG',
#      'pic': '',
#      'format': 'txt',
#      'changed': '2015-09-22 16:01:41'}}],
#   'PageIndex': 1,
#   'PageSize': 20,
#   'TotalCount': 53521,
#   'TotalPage': 2677}}
# 将Python对象转换为json字符串
res1 = json.dumps(res)
  1. 分块读取大文件,指定chunksize参数或iterator参数
# 分块读取大文件
# chunksize
agg1 = pd.read_csv('ex.csv',chunksize=10) # 一次读取10行
print(agg1.get_chunk())
#    a   b   c   d message
# 0  1   2   3   4   hello
# 1  5   6   7   8   world
# 2  9  10  11  12  python
agg1 = pd.read_csv('ex.csv',iterator=True)
agg1
# <pandas.io.parsers.TextFileReader at 0x1f2284e92e0>
agg1.get_chunk(2) # 读取前两行

数据数据清洗和准备

处理缺失数据
  1. 检测缺失数据,None和nan都能被检测
data1 = pd.Series(['a','b',np.nan,'d'])
# 检测缺失值 None和nan都能被检测
data1.isnull()
# 0    False
# 1    False
# 2     True
# 3    False
# dtype: bool
  1. 滤除缺失值
    (1)在Series中滤除缺失值
data1.dropna()
# 0    a
# 1    b
# 3    d
# dtype: object
data1[data1.notnull()]
# 0    a
# 1    b
# 3    d
# dtype: object

(2)在DataFrame中滤除缺失值

data2.dropna() # 删去所有含nan的行
data2.dropna(how='all') # 删去全为nan的行
data2.dropna(axis=1) # 删去所有含nan的列
data2.dropna(axis=1,how='all') # 删去全为nan的列

在以上代码中,需要注意的是,若一行中出现nan,则方法dropna能直接删除这一行,但若在其中指定how参数为all,则不一定能删除此行,此时只有在此行都为nan的情况下才能删除此行

# 创建新的dataframe作为例子
df = pd.DataFrame(np.random.randn(7,3))
df.iloc[:4,1] = np.nan
df.iloc[:2,2] = np.nan
#           0         1         2
# 0  0.735103       NaN       NaN
# 1 -0.659199       NaN       NaN
# 2 -1.130695       NaN  0.084843
# 3 -0.278393       NaN  1.526452
# 4 -1.526626 -0.570291  0.650891
# 5  1.156203 -0.739917 -0.924147
# 6  0.082499 -0.343313  1.748674
# 删除缺失值
df.dropna(thresh=2) # 删除缺失值为2的数据
#           0         1         2
# 2 -1.130695       NaN  0.084843
# 3 -0.278393       NaN  1.526452
# 4 -1.526626 -0.570291  0.650891
# 5  1.156203 -0.739917 -0.924147
# 6  0.082499 -0.343313  1.748674

以上代码主要讲解了dropna中thresh参数的用法,指定thresh缺失值,只有某一行中出现此数量的缺失值,此行才会被删除

  1. 填充缺失值
df.fillna(0) # 将所有的nan替换为0
df.fillna({1:0.9,2:0}) # 索引为1的列变为0.9,索引为2的列变为0
# 若在其中指定inplace=True可以直接修改原数据
#          0         1         2
# 0  0.735103  0.900000  0.000000
# 1 -0.659199  0.900000  0.000000
# 2 -1.130695  0.900000  0.084843
# 3 -0.278393  0.900000  1.526452
# 4 -1.526626 -0.570291  0.650891
# 5  1.156203 -0.739917 -0.924147
# 6  0.082499 -0.343313  1.748674

以上两种填充方法都是填充指定数据

df2.fillna(method='ffill')
#           0         1         2
# 0  0.699642  0.474279  1.306383
# 1  0.797090  0.294717  0.860378
# 2  0.974179  0.294717 -1.341360
# 3 -0.868484  0.294717  0.650945
# 4 -0.414434  0.294717  0.650945
# 5  1.678029  0.294717  0.650945
df2.fillna(method='ffill',limit=2)
#           0         1         2
# 0  0.699642  0.474279  1.306383
# 1  0.797090  0.294717  0.860378
# 2  0.974179  0.294717 -1.341360
# 3 -0.868484  0.294717  0.650945
# 4 -0.414434       NaN  0.650945
# 5  1.678029       NaN  0.650945

在fillna中指定method参数为ffill,可以自动填充nan为它上方的最近的不是nan的数据,若再设置limit参数,可以起到指定填充行数的效果

移除重复数据
  1. 检测重复数据
data.duplicated()
  1. 删除重复数据
data.drop_duplicates()

在出现重复数据的情况下,此种形式默认保留第一个出现的值

data.drop_duplicates(['k1']) # 根据某一列删除重复数据

在drop_duplicates方法中传入指定列,可以只根据某一列删除重复数据,只看这一指定列(或指定多列),若出现重复数据则进行删除,只保留第一个出现的值

data.drop_duplicates(keep='last') 

在drop_duplicates方法中设置keep参数为last,在出现重复数据的情况下,可以保留最后一个出现的值

利用映射或函数转换数据
  1. 根据map传入的字典对每行或每列进行转换
# 创建dataframe
data = pd.DataFrame({'food':['Apple','banana','orange','apple','Mango','tomato'],
                    'price':[4,3,3.5,6,12,3]})
#      food  price
# 0   Apple    4.0
# 1  banana    3.0
# 2  orange    3.5
# 3   apple    6.0
# 4   Mango   12.0
# 5  tomato    3.0
meat = {'apple':'fruit',
       'banana':'fruit',
       'orange':'fruit',
       'mango':'fruit',
       'tomato':'vagetables'}
data['class'] = data['food'].str.lower().map(meat)
#      food  price       class
# 0   Apple    4.0       fruit
# 1  banana    3.0       fruit
# 2  orange    3.5       fruit
# 3   apple    6.0       fruit
# 4   Mango   12.0       fruit
# 5  tomato    3.0  vagetables
  1. 根据map传入的函数对每行或每列进行转换,能与上面的方法产生相同的效果
data['class1'] = data['food'].map(lambda x:meat[x.lower()])
#      food  price       class      class1
# 0   Apple    4.0       fruit       fruit
# 1  banana    3.0       fruit       fruit
# 2  orange    3.5       fruit       fruit
# 3   apple    6.0       fruit       fruit
# 4   Mango   12.0       fruit       fruit
# 5  tomato    3.0  vagetables  vagetables
替换值
# 创建Series
data = pd.Series([1,-999,2,-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. 与重新索引相区分,重新索引只能使用以前的索引名(只是改变顺序),若使用新的索引名则全为nan
# 创建dataframe
data = pd.DataFrame(np.arange(12).reshape((3,4)),
                   index=['Beijing','Tokyo','New York'],
                   columns=['one','two','three','four'])
#           one  two  three  four
# Beijing     0    1      2     3
# Tokyo       4    5      6     7
# New York    8    9     10    11
# 重新索引
data.reindex(['Beijing','New York','Tokyo'])
#           one  two  three  four
# Beijing     0    1      2     3
# New York    8    9     10    11
# Tokyo       4    5      6     7
  1. 使用map方法进行轴索引的重命名,在原有数据上直接进行修改
# 大写操作
tran = lambda x:x[:4].upper()
data.index = data.index.map(tran)
print(data)
#       one  two  three  four
# BEIJ    0    1      2     3
# TOKY    4    5      6     7
# NEW     8    9     10    11
  1. 使用rename方法进行轴索引的重命名,返回新的对象
# rename
data.rename(index=str.title,columns=str.upper)
#       ONE  TWO  THREE  FOUR
# Beij    0    1      2     3
# Toky    4    5      6     7
# New     8    9     10    11

# 结合字典型对象对标签更新
data.rename(index={'TOKY':'东京'},columns={'three':'第三年'})
#       one  two  第三年  four
# BEIJ    0    1    2     3
# 东京      4    5    6     7
# NEW     8    9   10    11
离散化和面元划分
  1. 使用cut函数进行面元划分
age = [20,22,25,31,61,45,41,32]
bins = [18,25,35,60,100]
cats = pd.cut(age,bins)
cats
# [(18, 25], (18, 25], (18, 25], (25, 35], (60, 100], (35, 60], (35, 60], (25, 35]]
# Categories (4, interval[int64]): [(18, 25] < (25, 35] < (35, 60] < (60, 100]]
cats.codes
# array([0, 0, 0, 1, 3, 2, 2, 1], dtype=int8)
cats.categories
# IntervalIndex([(18, 25], (25, 35], (35, 60], (60, 100]],
#               closed='right',
#               dtype='interval[int64]')
pd.value_counts(cats)
# (18, 25]     3
# (35, 60]     2
# (25, 35]     2
# (60, 100]    1
# dtype: int64
pd.cut(age,[18,26,36,61,100],right=False) # 指定右侧是开区间
# 面元名称
names = ['青年','年轻人','中年','老年']
pd.cut(age,bins,labels=names)
# ['青年', '青年', '青年', '年轻人', '老年', '中年', '中年', '年轻人']
# Categories (4, object): ['青年' < '年轻人' < '中年' < '老年']

data = np.random.rand(20)
pd.cut(data,4,precision=2) # precision指定小数位数

bins中是划分的面元,使用cut函数可以将数据与面元一一对应,将数据对应到相应面元中,默认区间左开右闭,可以设置right参数调整为左闭右开,同时面元的名称也可以通过labels参数进行设置
2. 使用qcut函数进行面元划分

# qcut函数 可以得到大小相等的面元
data = np.random.rand(1000)
cats = pd.qcut(data,4)
pd.value_counts(cats)
# (0.75, 0.999]         250
# (0.505, 0.75]         250
# (0.232, 0.505]        250
# (-0.000773, 0.232]    250
# dtype: int64
# 按比例进行面元划分
cats = pd.qcut(data,[0,0.1,0.5,0.9,1.])
pd.value_counts(cats)
# (0.505, 0.904]        400
# (0.102, 0.505]        400
# (0.904, 0.999]        100
# (-0.000773, 0.102]    100
# dtype: int64

与cut函数不同的是,qcut函数不直接指定划分的面元

检测和过滤异常值
  1. 通过调用abs方法获取绝对值,选出其中大于指定界限的数据
data[(np.abs(data)>3).any(1)]
# 选出包含绝对值大于3的数据的行
  1. 将超过指定界限的数据进行修改
data[np.abs(data)>3] = 3
# 将绝对值大于3的数据都修改为3
排列和随机采样
  1. 排列,首先利用permutation方法产生新顺序的数组,然后根据新顺序的数组对原数据进行重新排列
# 原数据
#     0   1   2   3
# 0   0   1   2   3
# 1   4   5   6   7
# 2   8   9  10  11
# 3  12  13  14  15
# 4  16  17  18  19
sam = np.random.permutation(5)
df.take(sam)
# 修改之后的数据
#     0   1   2   3
# 2   8   9  10  11
# 1   4   5   6   7
# 0   0   1   2   3
# 4  16  17  18  19
# 3  12  13  14  15
  1. 随机采样,sample函数可以随机选择指定行数的数据,另外若再设置replace参数为True,可以进行重复选择
df.sample(n=3)
#     0   1   2   3
# 2   8   9  10  11
# 3  12  13  14  15
# 4  16  17  18  19
ch = pd.Series([5,7,1,6,3])
ch.sample(n=10,replace=True)
# 3    6
# 2    1
# 4    3
# 1    7
# 1    7
# 2    1
# 3    6
# 1    7
# 4    3
# 1    7
# dtype: int64
字符串对象方法
  1. 分割字符串
val = 'a,b,c'
val.split(',')
  1. 去除分割字符串的空白符,包括\n
p = [x.strip() for x in val.split(',')]
  1. 字符串加法
f,s,t = p
f+'::'+s+'::'+t
# 'a::b::c'

'::'.join(p)
# 'a::b::c'
  1. 检测字符串
'c' in p
# True

val.index(',')
# 1

val.find(':') # 没有查找到返回-1,找到则返回下标位置
# -1
  1. 替换字符串
val.replace(',','::')
# 'a::b::c'
正则表达式
  1. 拆分
import re
text = "foo   bar\t  bat  \tqq"
re.split('\s+',text)
# ['foo', 'bar', 'bat', 'qq']

res = re.compile('\s+')
res.split(text)
# ['foo', 'bar', 'bat', 'qq']

reg = re.split(res,text)
# ['foo', 'bar', 'bat', 'qq']
  1. 模式匹配
    (1)findall方法:返回字符串中所有的非重叠匹配模式,findall方法返回的是由所有模式组成的列表
res.findall(text)
# ['   ', '\t  ', '  \t']

(2)match方法:从字符串起始位置匹配模式,还可以对模式各部分进行分组,如果匹配到模式,则返回一个匹配项对象,否则返回None

t1 = re.match('f',text)
print(t1)
# <re.Match object; span=(0, 1), match='f'>

(3)search方法:扫描整个字符串以匹配模式,如果找到则返回一个匹配项对象,与match不同,其匹配项可以位于字符串的任意位置,而不仅仅是起始处

t2 = re.search('b',text)
print(t2)
# <re.Match object; span=(6, 7), match='b'>
pandas的矢量化
pandas字符串函数
  1. 使用contains方法来进行字符串的查找(字符串包含内容)
data.str.contains('gmail')
# a    False
# b     True
# c     True
# d      NaN
# dtype: object
  1. 使用split方法对字符串进行分割
data.str.split('@')
# a        [dave, qq.com]
# b    [steve, gmail.com]
# c      [sam, gmail.com]
# d                   NaN
# dtype: object
  1. 使用findall方法来计算各字符串的模式列表
data.str.findall('@')
# a    [@]
# b    [@]
# c    [@]
# d    NaN
# dtype: object
  1. 使用切片方法对字符串进行截取
data.str[:5]
# a    dave@
# b    steve
# c    sam@g
# d      NaN
# dtype: object
总结
  1. 数据缺失,存在大量的空值:填充或者删除缺失数据
    (1)检测缺失数据
(data.isnull()).sum()

  (2)dropna

data.dropna(subset=['yuanjia'],inplace=True)

  (3)fillna

  1. 数据存在重复值:删除重复值
    (1)检测重复值
data.duplicated().sum()

  (2)删除重复值

data.drop_duplicates(inplace=True)
  1. 数据类型不统一:数据类型转换
  2. 部分数据包含数值和字符串:字符串处理
data['shoujia'] = data.shoujia.map(lambda x:float(x.replace('万','')))

data['shoujia'] = data.shoujia.map(lambda x:x.replace('万','')).astype('float64')
  1. 部分数据存在异常值:删除异常值
data.drop([4,9],inplace=True)
  1. 少数数据不利于分析:数据替换
  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值