Pandas Notes

Feb 27th, 2020 - Now

读取 CSV

pd.read_csv(filepath_or_buffer, sep, header, parse_dates, index_col, prefix, encoding)

参数: filepath_or_buffer: 字符串,或者任何对象的read()方法。这个字符串可以是URL,有效的URL方案包括http、ftp、s3和文件。可以直接写入"文件名.csv"。 sep: 分隔符,默认为 ',' header: 将行号用作列名,且是数据的开头。默认为0,即将读取的第一行作为每一列的列名。 注意当 skip_blank_lines=True 时,这个参数忽略注释行和空行。所以header=0表示第一行是非空的数据而不是文件的第一行。若令 header=None 则第一行被当作数据,df的列名为序号 1,2,3... parse_dates: 布尔类型值 or int类型值的列表 or 列表的列表 or 字典(默认值为 FALSE) 1. True:尝试解析索引 2. 由int类型值组成的列表(如[1,2,3]):作为单独数据列,分别解析原始文件中的1,2,3列 3. 由列表组成的列表(如[[1,3]]):将1,3列合并,作为一个单列进行解析 4. 字典(如{'foo':[1, 3]}):解析1,3列作为数据,并命名为foo

squeeze: 布尔值,默认FALSE TRUE 如果被解析的数据只有一列,那么返回 Series 类型。 prefix: 给列名加的前缀 encoding: 导入出现乱码的时候使用,常用的有 'utf-8', 'gbk'

写入 CSV

dataframe.to_csv(path_or_buf,sep,na_rep,mode,columns,header,index)

参数: path_or_buf: 字符串,放文件名、相对路径、文件流等; sep: 字符串,分隔符,跟read_csv()的一个意思 na_rep: 字符串,将NaN转换为特定值 mode: 默认模式是覆盖写,当 mode='a'追加写 columns: 列表,指定哪些列写进去 header: 默认header=0,如果没有表头,设置header=None index: 关于索引的,默认True,写入索引

Dataframe

list 转化 dataframe

a = [['a', '1.2', '4.2'], ['b', '70', '0.03'], ['x', '5', '0']]  
df = pd.DataFrame(a, columns=['one', 'two', 'three'])

DataFrame 转 Numpy

df=pd.DataFrame(xxx)

# 三种方式
1. df.values # Not Callable
2. df.as_matrix()
3. np.array(df)

Numpy 转 DataFrame

mat = np.random.rand(3, 4)

df = pd.DataFrame(mat, columns=('colA', 'colB', 'colC', xxx)) # 给列命名

插入一行

貌似没有直接的插入选项,但是可以通过每次新建一个临时的 pd.DataFrame 然后 df.append() 实现操作:

df = pd.DataFrame(columns=('name', 'sex', 'id'))
name = '小王'
sex = '男'
id = '001'
df = df.append(pd.DataFrame({'name':[name],'sex':[sex],'id':[id]}), ignore_index=True)

几点重要的地方: 1. DataFrame.append() 不会对自己产生改变,要在前面加上 df= 。 2. append() 内部其实就是临时新建了一个实例,这里新建实例的方法是采用字典的方式 {'attr':[val], xxx } 对于每个属性后面跟上初始化的赋值 val,注意 val 要用 [] 括起来。 3. 要加上 ignore_index=True 否则可能新建的实例会有自带的索引导致多出一列,append之后得不到自己想要的结果。

遍历元素

例子:

   c1  c2  
0  10  100  
1  11  110  
2  12  120

Dataframe.iterrows()

按行遍历,将 DataFrame 的每一行迭代为 (index, Series) 对,可以通过 row[name] 对元素进行访问。

>>> for index, row in df.iterrows():
...     print(index)
...     print(row['c1'], row['c2'])
...

Output: 
0
(10, 100)
1
(11, 110)
2
(12, 123)

Dataframe.itertuples()

按行遍历,将 DataFrame 的每一行迭代为元组(tuple),可以通过 getattr(row, name) 对元素进行访问,比 iterrows() 效率高

>>> for row in df.itertuples():
...     print(getattr(row, 'c1'), getattr(row, 'c2'))
...

Output: 
(10, 100)
(11, 110)
(12, 123)

Dataframe.iteritems()

按列遍历,将DataFrame的每一列迭代为 (列名, Series) 对,可以通过 row[index] 对元素进行访问。

>>> for index, row in df.iteritems():
...     print(index)
...     print(row[0], row[1], row[2])
...

Output:
c1
(10, 11, 12)
c2
(100, 110, 123)

选取某一列或某一行

data['w']    #选择表格中的'w'列,使用类字典属性,返回的是 Series 类型

data.w       #选择表格中的'w'列,使用点属性,返回的是 Series 类型

data[['w']]  #选择表格中的'w'列,返回的是 DataFrame 类型

data[0:2]  #返回第1行到第2行的所有行,前闭后开,包括前不包括后

data[1:2]  #返回第2行,从0计,返回的是单行,通过有前后值的索引形式,
           #如果采用data[1]则报错,data[1:1]返回为空

data.iloc[-1]   #选取DataFrame最后一行,返回的是 Series
data.iloc[-1:]  #选取DataFrame最后一行,返回的是 DataFrame

给某列更名

  1. 读取文件的时候重命名 names = new_col,可以在读取文件的时候,给出新列名。

    new_col = ['new1', 'new2',... , 'newn']
    pd.read_csv('data', names = new_col, header=0)
  2. 全部重命名 columns = new_columns,新列名的长度必须与旧列名一致.

    new_col = ['new1', 'new2',... , 'newn']
    dataframe.columns = new_col
  3. 部分重命名 columns = dict,使用字典类型的数据对列进行重命名。

    dataframe.rename(columns = {"old_name": "new_name"})
    dataframe.rename(columns = {"old1": "new1", "old2":"new2"},  inplace=True)
  4. 因为dataframe的columns就是string类,所以可以直接使用 str.replace

    dataframe.columns = dataframe.columns.str.replace('' '', ''_'')

拼接操作

pandas.concat()

pandas 的顶级方法,提供了axis设置可用于 dataframe 间行方向(增加行,下同)或列方向(增加列,下同)进行内联或外联拼接操作。

concat(objs, axis=0, join='outer', join_axes=None, ignore_index=False,
           keys=None, levels=None, names=None, verify_integrity=False,
           copy=True)

参数说明: objs: 需要进行拼接的对象的集合,要用 [] 框起来 axis: 拼接轴方向,默认为0,沿行拼接;若为1,沿列拼接 join: 默认外联'outer',拼接另一轴所有的label,缺失值用NaN填充;内联'inner',只拼接另一轴相同的label; join_axes: 指定需要拼接的轴的labels,可在join既不内联又不外联的时候使用 ignore_index: 对index进行重新排序 keys: 多重索引

Dataframe.append()

dataframe 数据类型的方法,提供了行方向的拼接操作。

append(self, other, ignore_index=False, verify_integrity=False)

常用参数说明: other: 另一个dataframe ignore_index: 若为True,则对index进行重排 verify_integrity: 对index的唯一性进行验证,若有重复,报错。若已经设置了ignore_index,则该参数无效

Dataframe.join()

dataframe 数据类型的方法,提供了列方向的拼接操作,支持左联、右联、内联和外联四种操作类型。

join(other, on=None, how='left', lsuffix='', rsuffix='', sort=False)

常用参数说明: on: 参照的左边df列名key(可能需要先进行set_index操作),若未指明,按照index进行join how: {'left', 'right', 'outer', 'inner'}

  • 默认'left',即按照左边df的index(若声明了on,则按照对应的列);

  • 若为'right' 则按照右边的df;

  • 若'inner'为内联方式;

  • 若为'outer'为全连联方式。

sort: 是否按照join的key对应的值大小进行排序,默认False lsuffixrsuffix: 当left和right两个df的列名出现冲突时候,通过设定后缀的方式避免错误

Dataframe.merge()

pandas 的顶级方法,提供了类似于 SQL 数据库连接操作的功能,支持左联、右联、内联和外联等全部四种SQL连接操作类型。

pd.merge(left, right, how='inner', on=None, left_on=None, right_on=None,
          left_index=False, right_index=False, sort=False,
          suffixes=('_x', '_y'), copy=True, indicator=False,
          validate=None):

既可作为pandas的顶级方法使用,也可作为DataFrame数据结构的方法进行调用 常用参数说明: how: {'left', 'right', 'outer', 'inner'}

  • 默认'inner',类似于SQL的内联;

  • 'left' 类似于SQL的左联;

  • 'right' 类似于SQL的右联;

  • 'outer' 类似于SQL的全联。

on: 进行合并的参照列名,必须一样。若为None,方法会自动匹配两张表中相同的列名 left_on: 左边df进行连接的列 right_on: 右边df进行连接的列 suffixes: 左、右列名称前缀 validate: 默认None

  • "one_to_one" ,验证是否一对一关系

  • "one_to_many" ,验证是否一对多关系

  • "many_to_one",验证是否多对一关系

  • "many_to_many",验证是否多对多关系

SQL语句复习:

内联: SELECT a.*, b.* from table1 as a inner join table2 as b on a.ID=b.ID
左联: SELECT a.*, b.* from table1 as a left join table2 as b on a.ID=b.ID
右联: SELECT a.*, b.* from table1 as a right join table2 as b on a.ID=b.ID
全联: SELECT a.*, b.* from table1 as a full join table2 as b on a.ID=b.ID

删除某一行或某一列

dataframe.drop(label=['xxx','xxx','xxx'], axis=0, inplace=False)

参数: label: 是指定要删除的列或行的行号或列名称 axis: 删除的轴,默认为0,沿行方向进行删除,axis=1为沿列方向进行删除 inplace: 这个函数返回的是修改后的dataframe 但并不会改变自身,inplace=True的时候可以同时对自身进行修改

求交并差集

对于colums都相同的dataframe做过滤的时候,例如:

df1 = DataFrame([['a', 10, '男'], 
                 ['b', 11, '男'], 
                 ['c', 11, '女'], 
                 ['a', 10, '女'],
                 ['c', 11, '男']], 
                columns=['name', 'age', 'sex'])

df2 = DataFrame([['a', 10, '男'], 
                 ['b', 11, '女']],
                columns=['name', 'age', 'sex'])

取交集

print(pd.merge(df1,df2,on=['name', 'age', 'sex']))

取并集

print(pd.merge(df1,df2,on=['name', 'age', 'sex'], how='outer'))

取差集

差集即从df1中过滤df1在df2中存在的行 思路:将df2两次合并到df1中,然后删除重复项。 为什么要合并两次? 因为合并一次会求出对称差 ((A-B)$\cup$(B-A)) ,两次就能够将对称差中的 df2 也变成重复项从而删除掉。

df1 = df1.append(df2)  # 合并第一次
df1 = df1.append(df2)  # 合并第二次
df1 = df1.drop_duplicates(subset=['name', 'age', 'sex'],keep=False)
print(df1)

pandas 常用函数

DataFrame.drop_duplicates

Returns: deduplicated: DataFrame

e.g.

df=pd.DataFrame(xxx)
df.drop_duplicates(subset=['id','name'], keep=False) # 根据id和name双重判断,重复的一个都不留
df.drop_duplicates(subset=['id'], inplace=True) # 根据id判断,只留下第一个找到的重复值,并且赋值给自身

Series.groupby

Returns: GroupBy object

注意:这里的 groupby 的调用函数是 Series 不是 DataFrame,而 DataFrame需要通过 df['col'] 取值得到 Series。 注意:这里返回的是 Series 格式,只包括 被筛选的列key列

e.g.

# 一条记录有 id name commit_time
# 现在需要找到每个学生的最晚提交时间
# 由于 commit_time 是 date 格式所以可以直接比较大小
# 思路:根据id和name将所有commit_time进行分组然后取组内最大  
res = df['commit_time'].groupby([df['id'], df['name']]).max()  
或 res = df[['name', 'commit_time']].groupby(df['id']).max()

Reference

Last updated