Pandas数据处理笔记_Markdown版

引言:自从熟练了Markdown的语法后,写啥文档都好方便啊~一发不可收拾了.这两天又用到了pandas,翻出来之前做的笔记添加新内容的时候明显感觉很难受啊有木有,奈何CSDN也没有提供富文本编辑器生成的老博文直接转Markdown的功能,只好再一段一段的手工改一遍吧,之前那篇笔记就存档了,不再更新.以后都在这个里面追加记录新知识. -2019.11.12

读取CSV/Excel文件指定数据类型

import numpy as np

df = pd.read_csv('xxx.csv', encoding='gbk', dtype='str') # 指定每列数据都为str
df = pd.read_csv('xxx.csv', encoding='gbk', dtype={'b': object, 'c': np.float64}) # 指定b列为字符串类型,c列为float64类型

df = pd.read_excel('xxx.xls', encoding='gbk', dtype='str') # xls格式读取

dtype常用类型(使用numpy库提供的对象类型):

str 字符串
int64 整数
float64 浮点小数

修改DataFrame对象中列的数据类型

# 将df对象中的id列数据类型修改为字符串str类型
df['id'] = df['id'].astype(str)

# 使用字典映射{列:数据类型}实现批量修改多列数据类型
convert_dict = {
	'id': str,
	'value': float
	'value2': int
}
df = df.astype(convert_dict)

# 使用.apply和pd.to_numeric实现批量修改多列数据类型
df[['A', 'B', 'C']] = df[['A', 'B', 'C']].apply(pd.to_numeric)

# 对所有列批量转数字类型,自动判断int还是float,遇到非数字内容列则不转换
df = df.apply(lambda x:pd.to_numeric(x, errors='ignore'))

to_numeric() 中的errors参数效果:

  • 'raise' 转换失败抛出异常,程序中断
  • 'ignore' 转换失败会忽略不做修改,返回原来的数据类型
  • 'coerce' 转换失败会返回NaN

只对数字列进行sum汇总

df.sum(numeric_only=True)

对单个xlsx文件中全部工作簿进行合并

在一个xlsx文件中存在多个worksheet,其中的数据格式一致,将所有worksheet进行拼接合并,并导出csv

方法一:使用read_excel

import pandas as pd
df = pd.read_excel('xxx.xlsx', sheet_name=None, ignore_index=True)    #这里注意要带上后面的两个参数,否则会只加载第一个工作簿的数据
cdf = pd.concat(df.values())
cdf.to_csv('new.csv')

方法二:使用ExcelFile.pares

import pandas as pd

file = pd.ExcelFile('0629.xls')
print(file.sheet_names)
df = []
for sheet in file.sheet_names:
    df.append(file.parse(sheet))

cdf = pd.concat(df)
cdf.to_csv('concat.csv')
print('Job Done')

将DataFrame导出文件

df.to_excel('aaa.xlsx')    # 需要xlwt包的支持,用之前pip install xlwt一下,导出xlsx格式速度会比较慢,数据量大的时候不推荐
df.to_csv('bbb.csv', index=False, encoding='gb2312')    # index=False指定导出的文件中不带数据行号列,encoding指定文件编码,win下面必须指定gb2312,否则excel打开中文乱码

对DataFrame中的数据进行分类,然后获取每一分类的前n条

grouped = df.groupby(['class']).head(2)

使用列名对DataFrame进行数据选取

df[col]  #根据列名,并以Series的形式返回列
df[[col1, col2]]  #以DataFrame形式返回多列

使用iloc对DataFrame进行数据选取

# Single selections using iloc and DataFrame
# Rows:
data.iloc[0] # first row of data frame (Aleshia Tomkiewicz) - Note a Series data type output.
data.iloc[1] # second row of data frame (Evan Zigomalas)
data.iloc[-1] # last row of data frame (Mi Richan)
# Columns:
data.iloc[:,0] # first column of data frame (first_name)
data.iloc[:,1] # second column of data frame (last_name)
data.iloc[:,-1] # last column of data frame (id)

DataFrame保留小数点两位

df = df.round(2)

判断数据是否为NaN

# 判断name列是否为NaN空值
pd.isna(df['name'])

按条件修改数据

# 对df中name列='Dexter'的行对应的name列数据修改为'Tom'
df.loc[df['name']=='Dexter', 'name'] = 'Tom'

修改DataFrame中列的数据类型

查看DataFrame对象每个列的当前数据类型

df.dtypes

修改列的数据类型

df_obj['列名'].astype(int)
df_obj['列名'].astype(float)

批量修改多个列的数据类型

B204_cols = ['col1', 'col2', 'col3']
df[B204_cols] = df[B204_cols].apply(pd.to_numeric, errors='coerce')

实现SQL中distinct查询

df['列1'].unique()

删除指定列

df.drop(columns=['A', 'B'], axis=1, inplace=True)

# axis=1 表明删除列

# inplace=True 表明对df直接对象进行修改

根据条件进行数据筛选

df[df[col] > 0.5]  # 选择col列的值大于0.5的行
df[df.iloc[:,15]=='xxx']  # 选择第15列(列标从0开始)等于xxx的行
df[(df[col1] > 0.5) & (df[col2] > 1)]    # 多条件筛选

查看DataFrame对象数据总行数

len(df)

Series类型对象合并两列数据

在这里插入图片描述
Series A和B进行合并计算

s1.combine_first(s2)

DataFrame相减处理(集合处理,不是数据减法计算)

How to remove a pandas dataframe from another dataframe, just like the set subtraction:

a=[1,2,3,4,5]
b=[1,5]
a-b=[2,3,4]

And now we have two pandas dataframe, how to remove df2 from df1:

In [5]: df1=pd.DataFrame([[1,2],[3,4],[5,6]],columns=['a','b'])
In [6]: df1
Out[6]:
   a  b
0  1  2
1  3  4
2  5  6

In [9]: df2=pd.DataFrame([[1,2],[5,6]],columns=['a','b'])
In [10]: df2
Out[10]:
   a  b
0  1  2
1  5  6

Then we expect df1-df2 result will be:

In [14]: df
Out[14]:
   a  b
0  3  4

Use pd.concat followed by drop_duplicates(keep=False)

pd.concat([df1, df2, df2]).drop_duplicates(keep=False)

It looks like

   a  b
1  3  4

续接两个Series对象

s1 = pd.Series([1,2,3])
s2 = pd.Series([2,5,6,7,8])
s = s1.append(s2)
# s:[1,2,3,2,5,6,7,8]

统计查看DataFrame/Series重复数据

例如上面的拼接后的s对象,其中的数值2是存在重复的,那么要查看的话这样操作:

>>> s
0    1
1    2
2    3
0    2
1    5
2    6
3    7
4    8
dtype: int64
>>> s.duplicated()    # 查看重复情况,不过这个结果看起来很不友好的,主要是用于获得重复数据的bool结果
0    False
1    False
2    False
0     True
1    False
2    False
3    False
4    False
dtype: bool
>>> s[s.duplicated()]    # 查看重复的具体数据
0    2
dtype: int64
>>> s[s.duplicated()].count()    # 统计重复数据数量
1
>>> s[s.duplicated(keep=False)]    # 加上参数keep=False,效果是只保留所有重复的数据

Series转DataFrame类型

Series对象就是一个一维数组而已,是没有列名属性的,转换成DataFrame对象加上列名

s.to_frame('列名')

根据指定列对两个DataFrame进行相减处理去除重复行

有两个DataFrame对象df1是完整数据,df2是一个Series转换过来的DataFrame对象,其实就一列,现在想从df1中找出所有电话列=df2中数据的行删除掉,得到期望结果
在这里插入图片描述

result = pd.concat([df1,df2], ignore_index=True, sort=False).drop_duplicates(subset='电话', keep=False)

对DataFrame分组后再随机抽取行

按照‘乡镇’列进行分组,然后每一组里面随机抽取500行数据

import pandas as pd
rnd_size = 500  #随机抽取样本数量
df = pd.read_csv('cmcc_all.csv')
result = df.groupby('乡镇').apply(lambda x: x.sample(rnd_size))
result.to_csv('随机抽取结果.csv')
print('导出完成')

分组统计

对下面这张表按县区进行分组,然后统计问题1~问题4各有多少个(计数)

县区 问题1 问题2 问题3 问题4
汤阴 1 1 0 1
内黄 0 0 1
汤阴 1 0 0 1
汤阴 0 0 1
>>> df
   县区  问题1  问题2  问题3  问题4
0  汤阴    1    1    0  1.0
1  内黄    0    0    1  NaN
2  汤阴    1    0    0  1.0
3  汤阴    0    0    1  NaN
>>> gp = df.groupby('县区').count()
>>> gp
    问题1  问题2  问题3  问题4
县区
内黄    1    1    1    0
汤阴    3    3    3    2
>>> gp = df.groupby('县区').sum()
>>> gp
    问题1  问题2  问题3  问题4
县区
内黄    0    0    1  0.0
汤阴    2    1    1  2.0

计数结果:

县区 问题1 问题2 问题3 问题4
内黄 1 1 1 0
汤阴 3 3 3 2

实现Excel中Vlookup效果

在这里插入图片描述
将df1和df2的A列进行关联查询,得到result中的结果

>>> df1 = pd.DataFrame(columns=['A', 'B'], data=[[10,'Tom'],[11,'Kate'],[12,'Jack'],[13,'Claire']])
>>> df1
    A       B
0  10     Tom
1  11    Kate
2  12    Jack
3  13  Claire
>>> df2 = pd.DataFrame(columns=['A', 'C'], data=[[9,'Good'],[10,'Bad'],[11,'Good'],[12,'Bad'],[13,'Bad']])
>>> df2
    A     C
0   9  Good
1  10   Bad
2  11  Good
3  12   Bad
4  13   Bad
>>> result = df1.merge(df2, on='A', how='left')
>>> result
    A       B     C
0  10     Tom   Bad
1  11    Kate  Good
2  12    Jack   Bad
3  13  Claire   Bad

数据透视图之堆叠(stack)分组统计实例

有这样的原始数据:

xz q1 q2 q3
内黄 A B B
汤阴 A B B
水冶 B A A
滑县 A B A
滑县 C C C
滑县 C C C
水冶 A A B

期望效果:以xz为index,index,分别对q1,q2,q3中可能出现的数据结果进行分列进行计数统计
在这里插入图片描述

>>> df = pd.read_excel('test.xlsx',sheet_name=1)    # 数据放在test.xlsx第二个工作簿里面,故指定sheet_name=1(从0开始)
>>> df
   xz q1 q2 q3
0  内黄  A  B  B
1  汤阴  A  B  B
2  水冶  B  A  A
3  滑县  A  B  A
4  滑县  C  C  C
5  滑县  C  C  C
6  水冶  A  A  B

>>> result = (df.set_index('xz')).groupby(level='xz').apply(lambda x: x.apply(pd.value_counts)).unstack(level=1).fillna(0)

# 分行解释一下:
>>> result = (df.set_index('xz'))\    # 先设置index使用xz列
    .groupby(level='xz')\    # 以xz分组
    .apply(lambda x: x.apply(pd.value_counts))\    # 使用匿名函数lambda对数值进行计数统计
    .unstack(level=1)\    # 设置不堆叠
    .fillna(0)    # 对空置用0填充

>>> result.to_excel('result.xlsx')

上面的方法可以实现效果,但是如果q1~q3中可能存在的值不是都一样是A,B,C这三种情况的话,比如说q1可能的值是A,B,C,而q2可能的值是X,Y,Z
这样的话上述方法出来的结果就不对了,得用下面这种方法来构造,从stack overflow上面看的,具体每一步的解释没完全看懂,但是管用
原贴地址(https://stackoverflow.com/questions/44165629/pandas-pivot-table-for-multiple-columns-at-once)

这种情况:

xz q1 q2 q3
内黄 A X B
汤阴 A X B
水冶 B Y A
滑县 A Z A
滑县 C Y C
滑县 C X C
水冶 A Y B
# 如果还用刚才的方法来做的话,会把q1~q3中每一种可能出现的值都算成一列,就是这样:

>>> result = (df.set_index('xz')).groupby(level='xz').apply(lambda x: x.apply(pd.value_counts)).unstack(level=1)

>>> result
     q1                        q2                          q3
      A    B    C   X   Y   Z   A   B   C    X    Y    Z    A    B    C   X   Y   Z
xz
内黄  1.0  NaN  NaN NaN NaN NaN NaN NaN NaN  1.0  NaN  NaN  NaN  1.0  NaN NaN NaN NaN
水冶  1.0  1.0  NaN NaN NaN NaN NaN NaN NaN  NaN  2.0  NaN  1.0  1.0  NaN NaN NaN NaN
汤阴  1.0  NaN  NaN NaN NaN NaN NaN NaN NaN  1.0  NaN  NaN  NaN  1.0  NaN NaN NaN NaN
滑县  1.0  NaN  2.0 NaN NaN NaN NaN NaN NaN  1.0  1.0  1.0  1.0  NaN  2.0 NaN NaN NaN

# 所以应该用下面的方法来实现

>>> a = df.set_index('xz').stack().groupby(level=[0,1]).value_counts().unstack(level=[1,2]).sort_index(axis=1)

>>> a
     q1             q2             q3
      A    B    C    X    Y    Z    A    B    C
xz
内黄  1.0  NaN  NaN  1.0  NaN  NaN  NaN  1.0  NaN
水冶  1.0  1.0  NaN  NaN  2.0  NaN  1.0  1.0  NaN
汤阴  1.0  NaN  NaN  1.0  NaN  NaN  NaN  1.0  NaN
滑县  1.0  NaN  2.0  1.0  1.0  1.0  1.0  NaN  2.0

对上面例子中的多层列进行重命名和排序

# 对第一层的列重命名
a.columns.set_leves(['Q1', 'Q2', 'Q3'], level=0, inplace=True)

# 对第一层的列重新排序
cats = ['Q2', 'Q3', 'Q1']    # 先定义一个新的顺序
a = a.reindex(cats, axis=1, level=0)

这里需要注意reindex函数没有inplace的选项,所以要重新赋值回给a

自定义函数对指定列数据进行处理

现在有一个DataFrame df变量,其中有一列名为’电话’,里面的数据不太规矩,有的是空值,有的不是11位的手机号,现在需要将这些数据进行整理,通过自定义处理函数和apply(lambda)来实现:

import pandas as pd

df = pd.read_excel('1.xlsx')

# 自定义check函数,检查传入变量长度是否等于11位
def check(x):
    if len(str(x))!=11):
        return False
    else:
        return x


df['电话'].apply(lambda x: check(x))    # 这里可以先查看一下返回处理后的'电话'列中的数据

df['电话'] = df['电话'].apply(lambda x: check(x))    # 直接修改原df中的数据,将不合格数据替换为False

result = df[df['电话']!=False]    # 挑选出电话列合格的完整数据

# 附空值判断:
df[df['乡镇'].isnull()]    # 挑选出乡镇列中是空值的完整行

df[df['乡镇'].notnull()]    # 挑选出乡镇列中不是空值的完整行

对数字类型列进行字符串slice分割处理

现在有一名为"数据处理地"的列,内容类似410503100000,需要对其进行分割处理,只去开头的6位数字

df['数据处理地'].astype(str).str.slice(0,6)

由于导入的xls文件默认会将数据处理地这一列识别为int64数据类型,所以需要先使用.astype(str)将其转换为字符串类型,然后才能使用slice函数进行分割,slice()参数第一个是开始位置(首位为0),第二个参数为长度

对DataFrame的列重命名

# 直接重新赋值,注意需要将所有列名都写到数组中
df.columns = ['列1', '列2', '列3']

# 使用rename,可以只对指定列重命名
df.rename(columns={'A':'列1', 'B':'列2', 'C':'列3'}, inplace = True)
对DataFrame单元值进行替换
df.replace({'A':1.2, 'B':3.2}, inplace=True)

# 使用字典映射方式进行替换,将所有值为A的替换为1.2,值为B的替换为3.2
# inplace参数=True将直接修改当前的df对象内容

创建相同结构的空DataFrame

根据df1创建一个新的DataFrame,拥有和df1相同的索引,列,但是数据都是nan

df2 = pd.DataFrame().reindex_like(df1)
# 将nan填充为0,使用inplace参数就地处理(修改原df2对象),否则会返回一个新的df对象
df2.fillna(0, inplace=True)

两个DataFrame进行相加(数据加法计算)

如果两个要进行相加的df对象行和列完全相同,可以直接用df1 + df2这样的表达式进行计算

import pandas as pd

df1 = pd.DataFrame([(1,2),(3,4),(5,6)], columns=['a','b'])
#    a  b
# 0  1  2
# 1  3  4
# 2  5  6
df2 = pd.DataFrame([(10,20),(30,40),(50,60)], columns=['a','b'])
#     a   b
# 0  10  20
# 1  30  40
# 2  50  60
result = df1 + df2
#    a   b
# 0  11  22
# 1  33  44
# 2  55  66

如果列相同,index索引不一样

df1 = pd.DataFrame([(1,2),(3,4),(5,6)], columns=['a','b'], index=['d1', 'd2', 'd3'])
#     a  b
# d1  1  2
# d2  3  4
# d3  5  6
df2 = pd.DataFrame([(10,20),(30,40),(50,60),(70,80)], columns=['a','b'], index=['d1', 'd2', 'd3', 'd4'])
#      a   b
# d1  10  20
# d2  30  40
# d3  50  60
# d4  70  80
df1+df2
# 直接相加的话,d4行会变成NaN
#        a     b
# d1  11.0  22.0
# d2  33.0  44.0
# d3  55.0  66.0
# d4   NaN   NaN
df1.add(df2, fill_value=0)
# 使用.add并指定fill_value=0可以忽略df1中缺少的d4行(当做这行全是0继续相加),结果如下:
#        a     b
# d1  11.0  22.0
# d2  33.0  44.0
# d3  55.0  66.0
# d4  70.0  80.0

# 继续实验,行相同,列不同
df3 = pd.DataFrame([(10,20,1),(30,40,2),(50,60,3),(70,80,4)], columns=['a','b','c'], index=['d1', 'd2', 'd3', 'd4'])
#      a   b  c
# d1  10  20  1
# d2  30  40  2
# d3  50  60  3
# d4  70  80  4
df2+df3
# 直接相加结果和上面类似,多出来的c列全是NaN
#       a    b   c
# d1   20   40 NaN
# d2   60   80 NaN
# d3  100  120 NaN
# d4  140  160 NaN
df2.add(df3, fill_value=0)
# 结果也和上面一样
#       a    b    c
# d1   20   40  1.0
# d2   60   80  2.0
# d3  100  120  3.0
# d4  140  160  4.0
df1.add(df3, fill_value=0)
# 结果如预期一样,多出来的行和列也都填充上了数据
#        a     b    c
# d1  11.0  22.0  1.0
# d2  33.0  44.0  2.0
# d3  55.0  66.0  3.0
# d4  70.0  80.0  4.0

使用where方法替换指定条件的数据

df3 = pd.DataFrame([(10,20,1),(30,0,2),(50,60,3),(70,80,4)], columns=['a','b','c'], index=['d1', 'd2', 'd3', 'd4'])

In [16]: df3
Out[16]:
     a   b  c
d1  10  20  1
d2  30   0  2
d3  50  60  3
d4  70  80  4

df3的数据如上,现在需要进行列计算a/b,但是b列中存在可能=0的情况,如果出现这样的情况,需要使用c列中对应的值进行替换,具体实现:

df3['a']/df3['b'].where(df3['b']!=0,df3['c'])

这里需要注意的是条件只有在=False的时候才会返回后面的数据.where(条件, 条件=False时返回的数据)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章