还没决定

数据分析常用操作笔记——Python之Pandas包

数据分析虽说很多时候需要对业务和数据的理解,但其实大部分时候对数据的操作是相似(即使使用不同的工具,如Excel、Python、R等),像是数据清洗、表格结构修改、字段切分、分组计算等等。下面是使用Python中的Pandas包对数据分析常用操作的笔记。

数据读取

pandas读取文件后的数据集是一个DataFrame对象,该对象的每个列是一个Series对象

1
2
3
4
5
6
7
8
9
10
11
# pandas可读取很多文件格式
# 但一般读取数据的文件格式为:csv 和 excel
import pandas as pd
df = pd.read_csv("iris.csv",
sep=',',
names=["A","B","C","D"])
df = pd.read_excel("iris.xlsx",
sheetname='XXXX',
header=True)

数据探索

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
# 查看数据量和特征量
df.shape
>>> (68630, 14)
# 查看数据集的头5行
df.head()
# 查看数据集的尾5行
df.tail()
# 查看行名
df.index
>>> RangeIndex(start=0, stop=68630, step=1)
# 查看列名
df.columns
>>> Index(['行号', '仓库', '货号', '条码', '商品名称'], dtype='object')
# 几乎用不上吧
df.values
# 查看数据格式
df.dtypes
>>> 行号 int64
仓库 object
货号 int64
条码 object
# 计数:每个特征(列)的非空数量
df.count()
>>> 商品名称 68630
规格 6340
单位 67719
库存数量 68630
# 计数:对单个列(Series)的频数统计
df['仓库'].value_counts()
>>> 公司总部总仓库 2016
佛山南海万科店 938
深圳宝安兴业店 928
深圳宝安百年店 907
# 返回唯一值的数组
df['区域'].unique()
>>> array(['深圳', '东莞', '广州', '佛山', '江门', '成都', '四川'], dtype=object)
# 统计描述:可以对整个数据集(DataFrame),也可以对单个列(Series)
df.describe()
df['库存数量'].describe()
>>> count 68630.000000
mean 19.545230
std 248.819321
min -1600.000000
25% 2.000000
50% 5.000000
75% 14.000000
max 38080.000000
Name: 库存数量, dtype: float64
# 使用技巧
df.describe().astype(np.int64).T

数据清洗

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# 单列字段清洗-去空格
df['商品名称'] = df['商品名称'].map(lambda s : s.strip())
df['A']=df['A'].map(str.strip) # 去除两边空格
df['A']=df['A'].map(str.lstrip) # 去除左边空格
df['A']=df['A'].map(str.rstrip) # 去除右边空格
df['A']=df['A'].map(str.upper) # 转大写
df['A']=df['A'].map(str.lower) # 转小写
df['A']=df['A'].map(str.title) # 首字母大写
# 字段切分,并创建新特征
df.loc[:,"区域"] = df['仓库'].map(lambda s:s[0:2])
# 转换某特征(列)的数据格式
df['行号'] = df['行号'].astype(float)
# 转化时间格式
df['time']=pd.to_datetime(df['time'])

缺失值处理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
# 缺失值判断(在原数据对象以T/F替换)
df.isnull()
df['A'].isnull()
# 缺失值计数方法
# 方法一
df['A'].isnull().value_counts()
>>> True 68629
False 1
Name: A, dtype: int64
# 方法二
df['A'].isnull().sum()
>>> 68629
df.isnull().sum()
>>> 仓库 0
货号 0
条码 2
规格 62290
# 默认axi=0,how=‘any’,按行,任意一行有NaN就整列丢弃
df.dropna()
df.dropna(axis=1)
# 一行中全部为NaN的,才丢弃
df.driopna(how='all')
# 保留至少3个非空值的行:一行中有3个值是非空的就保留
df.dropna(thresh=3)
# 缺失值填充
df.fillna(0)

值替换

1
2
3
4
5
6
7
8
9
10
11
# 将df的A列中 -999 全部替换成空值
df["A"].replace(-999, np.nan)
#-999和1000 均替换成空值
obj.replace([-999,1000], np.nan)
# -999替换成空值,1000替换成0
obj.replace([-999,1000], [np.nan, 0])
# 同上,写法不同,更清晰
obj.replace({-999:np.nan, 1000:0})

重复值

1
2
3
4
5
6
7
8
9
# 返回布尔向量、矩阵
df['A'].duplicated()
df.duplicated()
# 保留k1列中的唯一值的行,默认保留第一行
df.drop_duplicated(["k1"])
# 保留 k1和k2 组合的唯一值的行,take_last=True 保留最后一行
df.drop_duplicated(["k1","k2"], take_last=True)

修改表结构

一般数据分析需要修改表结构都是在列上动手脚,注意操作有以下几种

  • 新增列
  • 修改列名
  • 丢弃列
  • 转化索引
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
# 创建新的列,一般使用loc
df.loc[:,"区域"] = df['仓库'].map(lambda s:s[0:2])
# 需求:创建一个新变量test2
# 1.petal_length>2 and petal_width>0.3 = 1
# 2.sepeal_length>6 and sepal_width>3 = 2 3.其他 = 0
df['test2'] = 0
df.loc[(df['petal_length']>2)&(df['petal_width']>0.3), 'test2'] = 1
df.loc[(df['sepal_length']>6)&(df['sepal_width']>3), 'test2'] = 2
# cut()数据分组,以连续值变量分组创建新特征
bins = [0, 5, 10, 15, 20] # 切分的边界
group_names = ['A', 'B', 'C', 'D'] # 每组的标签名
df['new'] = pd.cut(df['old'], bins, labels=group_names) # new就是分组新特征
# 修改列名称(字典方式)
df.rename(columns = {'旧':'新'},inplace=True)
# 丢弃指定的特征(列)
df.drop(['行号','条码'],
axis=1,
replace=True)
# 将列转化为索引
# 将columns中的其中两列:race和sex设置索引,race为一级,sex为二级
# inplace=True 在原数据集上修改的
# 默认情况下,设置成索引的列会从DataFrame中移除, drop=False将其保留下来
adult.set_index(['race','sex'], inplace = True)
# 取消列索引设置,并自动填充索引
adult.reset_index()

数据切片

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# []只能对 行(row/index) 切片,前闭后开
df[0:3]
df[:4]
df[4:]
# where布尔查找,建立在[]基础之上
df[df["A"]>7]
# isin()
# 返回布尔值
df["A"].isin([1,2,3])
df.loc[df['sepal_length'].isin([5.8,5.1])]
# loc :根据名称Label切片
# df.loc[A,B] A是行范围,B是列范围
df.loc[1:4,['petal_length','petal_width']]
# iloc:切位置,以序列号去切
df.iloc[1:4,:]
# ix:混切
# 名称和位置混切,但效率低,少用
df1.ix[0:3,['sepal_length','petal_width']]
1
2
3
4
5
6
7
# contains()模糊匹配
# 使用DataFrame模糊筛选数据(类似SQL中的LIKE)
# 使用正则表达式进行模糊匹配,*匹配0或无限次,?匹配0或1次
df_obj[df_obj['套餐'].str.contains(r'.*?语音CDMA.*')]
# 下面两句效果一致
df[df['商品名称'].str.contains("四件套")]
df[df['商品名称'].str.contains(r".*四件套.*")]

http://www.jb51.net/tools/zhengze.html

表格整合

不想写!

数据聚合&分组运算

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
# 单层分组
df.groupby('区域')
# 多层分组
df.groupby(['A','B'])
# 每个分组记录的计数
df.groupby('区域').size()
>>> 区域
东莞 7528
中山 520
佛山 5632
...
dtype: int64
# 分组数
len(df.groupby('区域'))
>>> 7
grouped = df.groupby(['A','B'])
# 对一个特征一次求得多个统计数
grouped['age'].agg([np.sum, np.mean, np.std])
# 对单一属性统计可以改列名
grouped['age'].agg({"求和":np.sum,"求平均数":np.mean})
# 对不同属性求不同的统计数
grouped.agg({'age':np.mean,'fnlwgt':np.sum})
1
2
3
4
5
6
7
# filter()
# 过滤分组计数少于1000的分组,在把分组计数大于1000的分组整合成一个DataFrame返回
con1 = lambda s : len(s) > 1000
df1 = grouped.filter(con1)
# 过滤分组age均值小于30的分组
con2 = lambda s : s['age'].mean()>30
df2 = grouped3.filter(con2)
1
2
3
4
5
# tansformation()
# 会返回一个数据集,这个数据集与group具有相同的索引以及大小 相当分组处理后合并
# 举例说明对数据集进行标准化:
zscore = lambda s : (s - s.mean())/s.std()
df = grouped.transform(zscore)

数据透视表

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
# crosstab() 一般只用与计数的数据透视表
pd.crosstab(index= df['A'],
columns = [df['B'],df['C']],
margins =True,
dropn=True)
# Produce 'pivot' table based on 3 columns of this DataFrame.
# Uses unique values from index / columns and fills with values.
# 感觉能使用的场景很少,因为不重复
df.pivot(index, columns, values)
df.pivot_table(values=None,
index=None,
columns=None,
aggfunc='mean',
fill_value=None,
margins=False,
dropna=True,
margins_name='All')
# 需求: index 是A ,columns 是 B,C, 我要求E的平均数并且有边
pd.pivot_table(df,
values = 'E',
index = 'A',
columns = ['B','C'],
aggfunc = [np.mean,np.sum],
margins = True)

Pandas专属

1
2
3
4
5
6
7
8
9
pd.get_dummies(data,
prefix=None,
prefix_sep='_',
dummy_na=False,
columns=None,
sparse=False,
drop_first=False)
df['time']=pd.to_datetime(df['time'])

数据导出

1
pd.to_csv("XXX.csv")