数据处理之pandas的学习

1.pandas中的几种数据结构

更多内容同步更新与个人博客系统:数据处理之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()

















你可能感兴趣的:(数据处理,python,pandas)