# -*- coding:UTF-8 -*-
__autor__ = 'zhouli'
__date__ = '2019/2/13 21:38'


import pandas as pd
firsts = pd.DataFrame(
    {
        'val1': 1.0,
        'val2': [1, 2, 3, 4],
        'val3': ["test", "trains", "tony", "stark"],
        'val4': 'iron_man'
    }
)
print(firsts)

>>>
   val1  val2    val3      val4
0   1.0     1    test  iron_man
1   1.0     2  trains  iron_man
2   1.0     3    tony  iron_man
3   1.0     4   stark  iron_man

可以看到的是

①pandas会自动帮我们做好了填充,非常方便,但是这也是一个容易出错的点

②默认会生成默认索引

③这种方式是以列的形式赋值

 

 

pandas的数据结构:

Pandas的基本数据结构是Series和DataFrame,顾名思义,Series就是序列,类似一维数组

DataFrame则是相当一张二维表格,类似二维数组,他的每一个列都是一个Series。为了定位Series中的元素,pandas提供了index对象,每一个Series都会带一个对应的index,用于标记不同的元素,index的内容不一定是数字,可以是字母,中文等,类似SQL的主键。

类似的DataFrame相当于多个带有同样index的series的组合(本质是series的容器),每个Series都带有唯一的表头,用来标识不同的Series

pd.Series([1,2,3,4])
pd.Series([1,2,3,4], index=['a', 'b', 'c', 'd'])
pd.Series({'a':1, 'b':2})

Series是将list和dict结合在一起的新数据类型,

就相当于把array多增加了一个标签索引

st=pd.Series([1,2,3,4], index=['a', 'b', 'c', 'd'])
st[['a', 'b']]  # 花式索引
st['a']  # 标签索引
st[0]  # 下标索引

这样做的好处是什么定位到一个表格中将列名作为标签索引

另外Series默认是标签索引!

举个栗子:

sr = pd.Series(np.arange(20))
sr2 = sr[10:].copy()

sr是什么?

sr2是什么?

那么sr2[10]结果为10

因为[]内默认是按照标签索引来解释,那如果就想用默认的索引怎么办?

sr2.iloc[]代表使用下标(当有冲突的时候)

sr2.loc[]代表使用标签

 

Series---数据对齐

sr1 = pd.Series([12, 23, 34], index=['c', 'a', 'd'])
sr2 = pd.Series([11, 20, 10], index=['d', 'c', 'a'])
sr1 + sr2

这种情况的index必须是一致的如果有不相同的部分就会出现NaN

那如果不想变成NaN咋办呢?

sr1 = pd.Series([12, 23, 34], index=['c', 'a', 'd'])
sr2 = pd.Series([11, 20, 10], index=['b', 'c', 'a'])

 也就是如何让在索引‘b’处的值为11,在索引‘d’处的值为34呢?

那就是使用pandas提供的算术方法:sub,add,div, mul

比如上面的例子:sr1.add(sr2, fill_value=0)如果不加fill_value还是一样的,fill_value是将不存在的赋值为0

 

 

Series---缺失值的处理

 可以先通过isnull()方法来判断是不是NaN

与此相反的是还有notnull()方法

sr.notnull()

当然再用花式索引就可以过滤出非缺失值

sr[sr.notnull()]

更加直接的是可以使用sr.dropna()

一样可以过滤掉缺失值

那如果不去掉缺失值sr.fillna(0)

 将缺失值赋值为0

但是如果是趋势图,赋值为0就会不连续,因此一般取平均值就可以表达为sr.fillna(sr.mean())

在pandas中sr.mean()默认会跳过NaN取平均值

 

Series小结:

① 是数组字典的结合体(支持下标和标签索引)

② 整数索引loc和iloc(解释为下标还是标签)

③ 数据对齐(不对齐出现NaN)

④ 确实数据的处理:

    1,扔掉dropna(),或者dropna(subset=['列名'])

    2,赋值fillna()

 

 

 

DataFrame()

 见下方例子:

那么如何按照行的形式来建立数据呢?

pd.DataFrame(
    data=None,  # 数据列表,字典格式时直接同事提供变量名
    columns=None  # 变量名列表
)
import pandas as pd

data = [
    [1, "test"], [2, "trains"], [3, "tony"], [4, "stark"],
    ]
colums = ["val1", "val2"]
rows = pd.DataFrame(
    data=data,  # 数据列表,字典格式时直接同事提供变量名
    columns=colums  # 变量名列表
)
print(rows)
>>>
   val1    val2
0     1    test
1     2  trains
2     3    tony
3     4   stark

 

结合起来Series

pd.DataFrame({"one": pd.Series([1, 2, 3], index=['a', 'b', 'c']), "two": pd.Series([1, 2, 3, 4], index=['b', 'a', 'c', 'd'])})

DataFrame的常用属性

① index 获取行索引

② T 转置(行列交换)

③ colums 获取列索引

④ values 获取值数组

⑤ describe() 获取快速统计

DataFrame的切片和取值

df.loc[‘a, ‘one’]  默认是先是行后是列

不要使用df['one']['a']这种方式

 那如果需要切一行那就是df.loc['a',:] ,意思为行是a,列是全部;等同于df.loc['a',]

 

缺失值的处理:

df.dropna()

①如果仅删除一行全是NaN的数据的时候传递参数df.dropna(how='all')

 

 

DataFrame的去重:

在大多数的时间,数据中会存在大量重复的数据,在做分析之前需要进行去重:

data = pd.DataFrame({'k1': ['one']*3+['two']*4, 'k2': [3,2,1,3,3,4,4]})

使用data.drop_duplicates()

可以看到,他在默认的情况下会将完全相同的行进行去重

当加上参数之后,subset代表的是当此值重复,pandas就认为是重复的,keep是决定保留哪一个,一般在使用keep的时候先用sort_values进行排序

如果需要查看重复的行

data[data.duplicated()]  # 查看重复的行

 

删除已有的列:

datas = pd.read_excel(r'C:\Users\lenovo\Desktop\高校信息.xlsx', encodinh='gbk')
datas.drop(['名次', '类型'], axis=1)

当然后面写的axis=1或者axis='columns'都是指按照列来处理

 

 

对列进行重命名:

datas.rename(columns={'学校名称': '大学名称','总分': '大学总分'})

 

 

pandas的分组技术:

说不清楚,直接看图吧

 

 

datas = pd.read_excel(r'C:\Users\lenovo\Desktop\高校信息.xlsx', encodinh='gbk')
data = datas[['名次', '类型', '学校名称', '所在城市', '所在省份']]
data.head()

比方计算各省的高校数量:

data[['学校名称']].groupby(data['所在省份']).count()

再比如,计算各高校所在城市的数量,并且从高到低排序前十名:

data[['学校名称']].groupby(data['所在城市']).count().sort_values('学校名称', ascending=False).head(10)

那如果想要知道各个省份大学名次之和呢?

data[['名次']].groupby(data['所在省份']).sum().sort_values('名次', ascending=False).tail(10)

当然我们还是可以使用自定义的函数进行聚合,首先需要自定义一个函数

def t_ranges(arr):
    return arr.max()-arr.min()
data[['名次']].groupby(data['所在省份']).agg(t_ranges).sort_values('名次', ascending=False).head(10)

注意,这里使用了agg()函数,agg函数还指出传入多个函数

data[['名次']].groupby(data['所在省份']).agg(['sum', 'mean','max',t_ranges]).tail(10)  # 在这里,agg里面传入列表,但是需要传入str字符串

在agg()函数中不仅可以应用同一种函数,还可以通过不同的列应用不同的求解函数,下面需要分别对名次和类型应用不同的统计函数,并输出不同列的数据,

这是可以通过agg自定义函数实现,只需要传入以列名为键值得字典

data[['名次', '类型']].groupby(data['所在省份']).agg({'名次': [t_ranges],'类型':['count']}).head()

agg()函数返回的不是DataFrame格式的,使用apply()函数

data.groupby(data['所在省份']).apply(lambda x: x[:3]).head(9)  # 在这里传入一个匿名函数,返回按照省份的前三个高校的信息

 

 

pandas的pivot_table(index="XXX", values=["ss", "dd"].aggfunc=np.sum)

index代表统计的数据是以XXX为基础的

values代表统计的数据和XXX之间的关系

aggfunc代表上述两个量之间的关系

 

pandas的常用函数:

①mean()方法

这个方法是用于求平均值df.mean()会自动忽略NaN

如果是行求平均值的话只需要加上一个参数df.mean(axis=1)即可

②sum()方法(同理上面)

③排序sort_values(by='two')  参数ascending=False倒序排列;如果是多列排序的话by可以传入列表(后面如果加上参数inplace=True,就代表用排好序的数据覆盖原始数据)

④按照索引排列sort_index(axis,……ascending)

Numpy的通用函数同样适合pandas

 

 

pandas的时间对象处理

pd.to_datetime(['2001-01-01', '2010/Feb/02'])
>>>
DatetimeIndex(['2001-01-01', '2010-02-02'],dtype='datetime64[ns]', freq=None)

to_datetime是可以传入数组或者是列表,批量处理时间

pd.date_range()

参数start是开始时间,end为结束时间;如果不指定end,那么periods就是代表长度

freq表示频率,这个就是控制periods,‘H’是小时,‘W’是周,‘W-MON’代表每周一,‘B’代表工作日

就是去除周六周天工作日,‘SM’代表半个月,‘T’是分钟,‘S’是秒,‘A’是年;

更离谱的是freq可以写成1h20min

pd.date_range('2010-01-03', periods=60, freq='1h20min')

 

 

时间序列:

我们可以看到date_range产生的是DatetimeIndex,也就是可以说当做series的索引

sr = pd.Series(np.arange(100), index=pd.date_range('2019-01-01',periods=100))

但是可以看到的是索引貌似是字符串,但是我们使用index方法看一下sr.index

他成为一个时间序列了,那有什么好处呢?

①我想查找所有2019年3月的数据

sr['2019-03']

 

如果仅仅看年就是sr['2019']

sr['2001':'2019-03-08'] 都是可以的

也可以按照周啊,天啊进行重列查看情况

sr.resample('M').sum()

 

文件的读取:

利用pandas读入文本格式数据文件

import pandas as pd

pd.read_csv(
    filepath_or_buffer='',  # 要读入文件的路径
    sep=',',  # 列分隔符,也可以传递正则表达式
    header='infer',  # 指定数据中第几行作为变量名,如果是None就是自动生成列名
    names=None,  # 自定义变量名列表, 
    index_col=None,  # 将会被用作索引的列名,多列时只能使用序号列表
    usecols=None,  # 指定只读入某些列,使用索引列表或名称列表均可
    # (0, 1, 3), ["名次", "学校名称", ""]
    encoding=None,  # 读入文件的编码方式
    na_values='',  # 指定将被读入为缺失值的数值列表,默认下列数据被读入,比如表格中None就读为NaN
    '''
    '','#N/A','#N/A N/A', '#NA', 'NULL'等
    '''
parse_dates=True, # 将表中能解释为时间序列的列解释为时间序列,也可以传递列名
) pd.read_table() # 更加通用的文本读取命令

读取CSV格式的文件,也是可以通用于文本文件的读取

那这两个方法有什么读取文本的命令基本上一致,最大的区别的地方在于sep

read_csv是',',而另一个是sep='\t',即tab符号

举个栗子:

这个是中国高校排行榜

high_school = pd.read_csv("high_school.csv", encoding='gbk')
print(high_school)

结果如下:

 

如果不适用read_csv,而是采用read_rable

结果就是这样

但是注意的是,table是按照\t来的,所以read_table的读取方式是整行读取,所以没有分割

 

数据的导入与导出:

1,Excel文件的读入:

high_school = pd.read_excel("high_school1.xlsx", sheet_name="full")
print(high_school, high_school.describe()  # 查看数据的基本情况)

sheet_name写full或者不写都是一样的,因为默认都是读取第一个sheet

当sheet_name写0的时候也是相当于读取第一个sheet

 

 

读入统计软件数据集:

例如读SAS/Stata:

pd.read_sas()

pd.read_stata()

 

 

读入数据库的文件:

①读入数据表

pd.read_sql

pd.read_sql(
    sql='',  # 需要执行的sql语句/要读入的表名名称
    con='',  # SQLAlchemy连接引擎名称
    index_col=None, # 将被用作索引的列名称
    columns=None,  # 将提供表名称时,需要读入的列名称list
)
pd.read_sql(
    sql='basic',  # 表名为basic
    con=eng,  # SQLAlchemy连接引擎名称eng
)

数据的导出:

to_csv

参数有:

① sep  指定文件分隔符

② na_rep 指定缺失值转换的字符串,默认为‘’

③ header=False 不输出列名一行

④ index=False 不输出行索引一列

⑤ cols 指定输出的列,传入列表

 

 

pandas和matplotlib

df.plot()

plt.show()

 

posted on 2019-02-16 22:26  人生苦短use,what?  阅读(728)  评论(0编辑  收藏  举报