更多内容同步更新与个人博客系统:数据处理之pandas的学习
import pandas as pd
import numpy as np
# 数据结构
'''
pandas中一共有三种数据结构,分别为:Series,DataFrame和MultiIndex
其中Series是一维数据结构,DataFrame是二维数据表结构,MultiIndex是三维数据结构
'''
# 1.Series
'''
Series是一个类似于一维数组的数据结构,它能够保存任何类型的数据,比如浮点,整数等
主要由一组数据和与之相关联的索引两部分组成
API:
pd.Series(data=None,index=None,dtype=None)
参数:
.data:传入的数据,可以是ndarray,list等
.index:索引,必须是唯一的,且与数据的长度保持一致,如果没有传入索引参数,
则会默认创建一个0~N的整数索引
.dtype:数据类型
Series的属性
Series.index:获取索引
Series.values:获取数据值
'''
a = [i for i in range(10, 1000, 10)]
# 通过数组数据创建
a_series = pd.Series(a, )
print(f'a={a}]\na_Series=\n{a_series}')
# 通过字典数据创建
a_dict = {'a': 1, 'b': 2, 'c': 3}
a_dict_Series = pd.Series(a_dict)
print(f'a_dict={a_dict}\na_dict_Series=\n{a_dict_Series}')
# 获取索引
a_dict_index = a_dict_Series.index
print(f'a_dict_index={a_dict_index}')
# 获取数据值
a_dict_values = a_dict_Series.values
print(f'a_dict_values={a_dict_values}')
# 通过索引获取值
print(a_dict_Series['a'])
# 2.DataFrame
'''
DataFrames是一个类似于二维数组或表格的对象,既有行索引,也有列索引
.行索引,表名不同行,横线索引,叫index,0轴,axis=0
.列索引,表名不同列,纵向索引,加columns,1轴,axis=1
API:
pd.DataFrame(data=None,index=None,columns=None)
参数:
.index:行标签,如果没有传入索引参数,则会自动创建一个从0~N的整数索引
.columns:列标签,如果没有传入索引参数,则会自动创建一个从0~N的整数索引
属性:
DataFrame.shape:返回[index,columns]
DataFrame.index:返回行索引
DataFrame.columns:返回列索引
DataFrame.values:返回数据值
DataFrame.T:转置,行列互换
DataFrame.head(n=5):显示前n行,如果不输入n,默认显示前5行
DataFrame.tail(n=5):显示后n行,如果不输入n,默认显示后5行
索引操作:
修改索引:
DataFrame.index=newIndex
注:索引必须整体进行修改,不能只修改其中某一个索引
DataFrame.index[3]=newItemIndex(错误!!!)
1.设置索引
DataFrame.reset_index(drop=False)
参数:
drop:默认为False,不删除原来的索引,如果为True则删除,即用新索引替换
旧索引
2.以某列值设为新的索引
DataFrame.set_index(keys,drop=True)
参数:
.keys:列索引名称或列索引名称列表
.drop:默认删除原来的列
'''
b = np.random.randn(3, 3) # 3*3的数组
b_DataFrame = pd.DataFrame(b)
print(f'b=\n{b}\nb_DataFrame=\n{b_DataFrame}')
print(f'b_DataFrame.shape={b_DataFrame.shape}')
print(f'b_DataFrame.index={b_DataFrame.index}')
print(f'b_DataFrame.columns={b_DataFrame.columns}')
print(f'b_DataFrame.values=\n{b_DataFrame.values}')
b_DataFrame_T = b_DataFrame.T
print(f'转置后的:\n{b_DataFrame_T}')
print(f'显示前2行:\n{b_DataFrame.head(2)}')
print(f'显示后2行:\n{b_DataFrame.tail(2)}')
data_test = np.array(
[
[2010, 1, 120],
[2010, 2, 124],
[2010, 3, 123],
[2010, 4, 121],
[2012, 5, 167],
[2012, 6, 18],
[2013, 7, 20],
[2013, 8, 120],
]
)
data_test_index = [f'行{i}' for i in range(8)]
data_test_columns = ['年', '月', '数']
data_test_DataFrame = pd.DataFrame(data_test, index=data_test_index, columns=data_test_columns)
print(f'data_test_DataFrame=\n{data_test_DataFrame}')
# 将年这一列的数据设为索引 同时不删除原来的列
year_index = data_test_DataFrame.set_index('年', drop=False)
print(f'year_index=\n{year_index}')
# MultiIndex
'''
MultiIndex是三维的数据结构,多级索引(也称层次化索引),是pandas的重要功能,可以在
Series.DataFrame对象上拥有2个以及2个以上的索引
'''
# 创建MultiIndex
test_array = [[1, 2, 3], ['r', 'g', 'b']]
multiLndex = pd.MultiIndex.from_arrays(test_array,names=('num','col'))
print(multiLndex)
## 2.DataFrame的运算
import pandas as pd
# 读取数据
data = pd.read_csv('demo.csv')
# 算术运算
# 加法
print(data['序号'].head())
print(data['序号'].head().add(10)) # 给序号这一列的所有数据都加10
print(data['序号'].head() + 10)
# 逻辑运算
# 例 筛选出序号值大于560195290043的数据
print('*' * 50)
data2 = data[(data['序号'] > 560195290043) & (data['店铺的url'] != '空')].head()
print(data2)
# 逻辑运算函数
print('*' * 100)
data3 = data.query("序号>560195290043 & 店铺的url!='空'").head() # 筛选结果同上
print(data3)
print('*' * 100)
# isin
data4 = data['价格'].isin([576, '576', 380]).head()
print(data4)
# 统计运算
print(data.describe())
print('*' * 100)
# 统计函数
print(data['序号'].sum()) # sum求和
print(data['序号'].mean()) # mean平均值
print(data['序号'].median()) # median中位数
print(data['序号'].min()) # min最小值
print(data['序号'].max()) # max最大值
print(data['序号'].mode()) # mode众数
print(data['序号'].abs()) # abs绝对值
print('乘积', data['序号'].prod()) # prod乘积
print(data['序号'].std()) # std标准差
print(data['序号'].var()) # var方差
print(data['序号'].idxmax()) # idxmax最大值的索引值
print(data['序号'].idxmin()) # idxmin最小值的索引值
# 对于单个函数进行统计的时候,坐标轴还是按默认"Columns"(axis=0,default) 如果要对行"index"需要指定axis=1
## 3.累计统计函数
import pandas as pd
import matplotlib.pyplot as plt
from pprint import pprint
data=pd.read_csv('demo.csv')
#计算前n个数的和 cumsum
data2=data['序号'].cumsum()
print(data2)
data2.plot()
plt.show()
#cummax 计算前n个数的最大值
#cummin 计算前n个数的最小值
#cumprod #计算前n个数的乘积
#自定义函数
''':cvar
语法:
apply(func,axis=0)
.func:自定义的函数
.axis:默认是列,axis=1指定为行
'''
#例:定义一个对列求最大值-最小值的函数
def max_min(x):
# return x.max(x)-x.min(x)
return x*2
data['2*序号']=data['序号'].apply(lambda x:max_min(x),0)
pprint(f'data=\n{data}')
## 4.文件的读取和存储
import pandas as pd
#读取csv文件
data=pd.read_csv('demo.csv',usecols=['名称','价格']) #usecols指定要读取的列
print(data)
#写入文件
''':cvar
to_csv(path_or_buf=None,sep=",",columns=None,header=True,index=True,mode="w",encoding=None)
path_or_buf:文件路径
sep:分隔符,默认使用","隔开
columns:选择需要的列索引
header:是否写进列索引值
index:是否写进行索引值
mode:文件写入的方式 w:重写 a:追加
encoding:编码方式
'''
#会发现将索引存入文件当中,变成单独的一列数据,如果需要删除,可以指定参数index=False即可
data[:10].to_csv('demo2.csv',columns=['名称','价格'],index=False)
## hdf5文件的存储
import pandas as pd
''':cvar
HDF5文件的读取和存储需要指定一个键,值为要存储的DataFrame
pandas.read_hdf(path_or_buf,key=None,**kwargs)
从h5文件中读取数据
.path_or_buf:文件路径
.key:读取的键
'''
#一般情况下 读取hdf5文件需要依赖tables库 可以先提前安装好 pip install tables
data=pd.read_hdf('')
#存储文件
data.to_hdf(path_or_buf='',key='123')
#再次读取的时候,需要指定键的名字
new_data=pd.read_hdf('',key='123')
#注意:
'''
优先选择使用hdf5文件存储
.hdf5在存储的时候支持压缩,使用的方式是blosc,这个是速度最快也是pandas默认支持的
.使用压缩可以提高磁盘的利用率,节省空间
.hdf5还是跨平台的,可以轻松迁移到Hadoop上面
'''
## json文件的存储
import pandas as pd
'''
pandas.read_json(path_or_buf=None,orient=None,typ='frame',lines=False)
orient
'''
# 读取json
data = pd.read_json('data.json', orient='records', lines=False)
print(data)
# 保存json orient:指定json文件的存储格式,可选参数有:split records index columns values
data.to_json('demo3.json', orient='records', lines=True)
#lines:是否存储在多行 默认lines=False是存储在一行
## 5.缺失值的处理
import pandas as pd
import numpy as np
#处理缺失值的方法
'''
.获取缺失值的表示方式(NaN或者其他标记方式)
.如果缺失值的标记方式是NaN
判断数据中是否包含NaN:
pd.isnull(df)
pd.notnull(df)
存在缺失值:
1.删除存在的缺失值:dropna(axis='rows') #默认删除存在缺失值的行
注:不会修改原数据,需要接受返回值
2.替换缺失值:fillna(value,inplace=True) 无返回值
value:替换成的值
inplace:True:会修改原数据,False:不替换修改原数据,生成新的对象
.如果缺失值没有使用NaN标记,比如使用"?"
先替换"?"为np.nan,然后继续处理
'''
data=pd.read_csv('demo2.csv')
print(type(data))
#判断有误缺失值
isNull=np.any(pd.isnull(data)) #isnull:如果有一个缺失值就会返回True
isNull2=np.all(pd.notnull(data)) #notnull:如果有一个缺失值就会返回False
print(pd.isnull(data))
print(pd.notnull(data))
print(isNull)
print(isNull2)
#删除缺失项
# data2=data.dropna(axis=1) #axis=0:默认删除这一行 axis=1删除这一列
# print(data2)
#替换缺失值 例:用平均值替换掉缺失值
price_mean=data['价格'].mean()
data.fillna(price_mean,inplace=True)
print(data.index)
for i in data.columns:
print(data[i])
## 6.数据离散化
import pandas as pd
#API:pd.qcut(data,q)
'''
对数据进行分组,一般会与value_counts搭配使用,统计每组的个数
'''
#API:pd.cut(data,bins)
'''
自定义区间分组
'''
#API:Series.value_counts()
'''
计算分到每个组数据个数
'''
#读取数据
df=pd.read_csv('stock_day.csv')
#使用turnover列的数据
turnover=df['turnover']
#自动分组(均匀分组)
auto_cut=pd.qcut(turnover,10)
#查看每组的数量
bins_count=auto_cut.value_counts()
print(bins_count)
#自定义分组
bins=[0,1,3,5,7,9]
hand_cut=pd.cut(turnover,bins)
#查看每组的数量
bins_count2=hand_cut.value_counts()
print(bins_count2)
#one-hot编码
#把每个类别生成一个布尔列,这些列中只有一列可以为这个样本取值为1,其又别称为热编码
#API:pd.get_dummies(data,prefix=None)
'''
参数:
data:array-like,Series,DataFrame
prefix:分组名字
'''
dummies=pd.get_dummies(turnover,prefix='turnover')
print(dummies.head())
## 7.数据合并
import pandas as pd
# 如果数据是有多张表组成,那么有时候需要将不同的内容合并在一起分析
# API:pd.concat([data1,data2],axis=1)
'''
.data1,data2:需要合并的数据
.axis:合并方向默认为行索引
'''
data1 = pd.read_csv('stock_day.csv')
data2 = pd.read_csv('demo2.csv')
data = pd.concat([data1, data2], axis=1) #
print(data)
# API:pd.merge(left,right,how='inner',on=None)
'''
可以指定按照两组数据的共同键值对合并或者左右各自
参数:
left:DataFrame
right:另一个FataFrame
on:指定的共同键
how:按照什么方式连接
'''
left = pd.DataFrame({'key1': ['K0', 'K0', 'K1', 'K2'],
'key2': ['K0', 'K1', 'K0', 'K1'],
'A': ['A0', 'A1', 'A2', 'A3'],
'B': ['B0', 'B1', 'B2', 'B3']})
right = pd.DataFrame({'key1': ['K0', 'K1', 'K1', 'K2'],
'key2': ['K0', 'K0', 'K0', 'K0'],
'C': ['C0', 'C1', 'C2', 'C3'],
'D': ['D0', 'D1', 'D2', 'D3']})
# 左连接
left_connect = pd.merge(left, right, how='left', on=['key1', 'key2'])
print(left_connect)
# 右连接
right_connect = pd.merge(left, right, how='right', on=['key1', 'key2'])
print(right_connect)
# 内连接 默认连接方式是内连接
inner_connect = pd.merge(left, right, how='inner', on=['key1', 'key2'])
print(inner_connect)
# 外连接
outer_connect = pd.merge(left, right, how='outer', on=['key1', 'key2'])
print(outer_connect)
## 8.交叉表和透视表
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
# 交叉表
'''
交叉表用于计算一列数据对于另外一列数据的分组个数(用于统计分组频率的特殊透视表)
API:
pd.crosstab(value1,value2)
'''
# 透视表
'''
透视表是将原有的DataFrame的列分别作为行索引和列索引,然后对指定的列应用聚合函数
'''
df = pd.read_csv('stock_day.csv')
print(df.index)
# 将数据的列索引转化成对应的日期之后再转换成星期
week = pd.to_datetime(df.index).weekday
df['week'] = week
print(df['p_change'])
# 把p_change按照分为大于0和小于0的
p_n_data = np.where(df['p_change'] > 0, 1, 0)
df['p_n']=p_n_data
print(df)
#使用透视表实现 方法1
per_count2=df.pivot_table(['p_n'],index='week')
print(per_count2)
#方法2
#通过交叉表寻找两列数据的关系
count=pd.crosstab(week,p_n_data)
print(count)
#计算每个星期各自的总和 axis=1指定为行 astype转换为浮点型
sum_count=count.sum(axis=1).astype(np.float32)
print(sum_count)
#求百分比
per_count=count.div(sum_count,axis=0)
print(per_count)
#图片显示 stacked=True:堆积显示
per_count.plot(kind='bar',stacked=True)
plt.show()
## 9.分组与聚合
import pandas as pd
# 分组API
'''
df.groupby(key,as_index=False)
参数:
key:分组的列数据,可以多个
as_index:时候保留原列的数据,默认不保存
'''
col = pd.DataFrame(
{'color': ['white', 'red', 'green', 'red', 'green'], 'object': ['pen', 'pencil', 'pencil', 'ashtray', 'pen'],
'price1': [5.56, 4.20, 1.30, 0.56, 2.75], 'price2': [4.75, 4.12, 1.60, 0.75, 3.15]})
print(col)
# 方法1 按照color进行分组 分别求每组color下其他各列对应的最大值
df1 = col.groupby(['color'],as_index=True).max()
# 方法2 object进行分组 分别求每组object下price1下的最小值
df2 = col['price1'].groupby(col['object']).min()
print(df1)
print(df2)
## 10.案例一(星巴克)
import pandas as pd
import matplotlib.pyplot as plt
data=pd.read_csv('directory.csv')
# print(data.head())
# print(data.columns.values)
#统计各个国家的星巴克数量
country_count=data.groupby(['Country']).count()['Brand']
country_count.plot(kind='bar',figsize=(20,8),)
plt.xlabel('country')
plt.ylabel('num')
plt.title('country-number')
plt.show()
#统计各个省份/州的星巴克数量
province_count=data.groupby(['Country','State/Province']).count()['Brand']
province_count.plot(kind='bar',figsize=(200,8))
plt.show()
## 11.案例二(电影)
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
#读取数据
data=pd.read_csv('IMDB-Movie-Data.csv')
print(data.head().columns)
#1.获取所有电影的平均分
Rating_mean=data['Rating'].mean()
print(f'平均分:{Rating_mean}')
#导演的总人数
director_num=np.unique(data['Director']).size
print(f'导演的总人数:{director_num}')
#查看每个导演的作品数量
director_work_num=data.groupby(['Director']).count()['Title'].sort_values()
director_work_num.plot(kind='bar',figsize=(200,8))
plt.show()
#获取Rating和runtime的分布情况
rating_num=data['Rating']
runtime_num=data['Runtime (Minutes)']
plt, axes=plt.subplots(2,1,figsize=(20,8))
axes[0].hist(rating_num.values,bins=20)
axes[1].hist(runtime_num.values,bins=20)
#修改刻度
min_=data['Rating'].min()
max_=data['Rating'].max()
xticks=np.linspace(min_,max_,num=21)
axes[0].set_xticks(xticks)
min_=data['Runtime (Minutes)'].min()
max_=data['Runtime (Minutes)'].max()
xticks=np.linspace(min_,max_,num=21)
axes[1].set_xticks(xticks)
#标题
axes[0].set_title('Rating-hist')
axes[1].set_title('Runtime-hist')
#增加网格
axes[0].grid(linestyle='--',alpha=0.5)
axes[1].grid(linestyle='--',alpha=0.5)
plt.show()
#统计电影分类情况
genre=[i.split(',') for i in data['Genre'].values]
print(genre)
genre_unique=np.unique([i for j in genre for i in j])
print(genre_unique)
zeros=np.zeros((1000,genre_unique.size))
#创建一个DataFrame对象
genDF=pd.DataFrame(zeros,index=data['Title'].values,columns=genre_unique)
print(genDF.head())
print(np.unique(data.index.values).size)
for i in range(1000):
for k in genre[i]:
title=data['Title'][i]
genDF[k][title]=1
gen_sum=genDF.sum().sort_values(ascending=False)
gen_sum.plot(kind='bar',figsize=(20,8),colormap='cool',fontsize=16)
plt.show()