文章目录

  • 0. 前言
  • 1. Series
  • 1.1. 基本概念
  • 1.2. 构造对象Series
  • 1.3. 其他
  • 1.4. 根据一个Series构建其他Series
  • 2. DataFrame
  • 2.1. 基本概念
  • 2.2. 构建对象
  • 2.3. 行
  • 2.4. 列
  • 2.5. 其他操作
  • 3. 其他
  • 3.1. 读取文件
  • 3.2. 写文件


0. 前言

  • 参考《利用Python进行数据分析》第五章
  • pandas中数据结构组要分为SeriesDataFrame

1. Series

1.1. 基本概念

由一组数据(各种Numpy数据类型)以及一组与之相关的数据标签(即索引)组成。

1.2. 构造对象Series

# 默认索引为数字,从0开始编号
obj = Series([4, 7, -5, 3]) 

# 指定索引
obj2 = Series([4, 7, -5, 3], index=['d', 'b', 'a', 'c'])  

# 通过字典构建,key为索引,value为值
sdata = {'Ohio': 35000, 'Texas': 71000, 'Oregon': 16000, 'Utah': 5000}
obj3 = Series(sdata)  

# 输入字典,同时指定索引
# 索引中存在,字典中不存在的,值为NA
# 索引中不存在,字典中存在的,忽略
states = ['California', 'Ohio', 'Oregon', 'Texas']
obj4 = Series(sdata, index=states)

1.3. 其他

  • 对值可以直接进行类似Numpy的操作。
  • 多个Series之间的操作,会在算术运算中自动对齐不同的索引的数据。
  • 索引:修改索引可以直接通过赋值。如obj.index = ['Bob', 'Steve', 'Jeff', 'Ryan']
  • name属性,与pandas中其他功能有很大联系。

1.4. 根据一个Series构建其他Series

  • 其实,在DataFrame中添加新列的本质就是这个操作。
  • 字符串split操作,例如 df['image_name'].str.split("_").apply(lambda x: x[0])

2. DataFrame

2.1. 基本概念

  • 包含一组有序的列(Series对象),每列可以是不同的数值类型。
  • 既包含行索引又包含列索引。
  • 常用属性:
  • T
  • axes:查看行索引与列索引
  • info():基本信息

2.2. 构建对象

# 通过字典构建
# key为列索引,value为值(可以是列表或numpy对象,要求长度一样)
# 默认行索引为数字,从0开始编号
data = {'state': ['Ohio', 'Ohio', 'Ohio', 'Nevada', 'Nevada'],
        'year': [2000, 2001, 2002, 2001, 2002],
        'pop': [1.5, 1.7, 3.6, 2.4, 2.9]}
frame = DataFrame(data)

# 可以指定列索引
# 如果索引不存在,则该行为NaN
frame2 = DataFrame(data, columns=['year', 'state', 'pop', 'debt'],
                   index=['one', 'two', 'three', 'four', 'five'])
                   
# 通过嵌套字典构建
# 外层字典的key为列索引,内层字典的key为行索引
pop = {'Nevada': {2001: 2.4, 2002: 2.9},
       'Ohio': {2000: 1.5, 2001: 1.7, 2002: 3.6}}
frame3 = DataFrame(pop)

# 其他
# 二维ndarray(可添加行、列索引)
# 数组、列表、元组 组成的字典。
# numpy结构化数组
# Series字典
# 嵌套字典
# 字典或Series的列表
# 列表或字典组成的列表
# 另一个DataFrame

2.3. 行

  • 查看行索引/行名称:df.index
  • 普通查询(获取单行或多行信息)
  • 获取的结果是行对象,而不是Series。
# 切片获取,不能使用单个数字
frame[1:4]
# frame[1] # error

# irow + 行号,只能获取单行
frame.irow(0)

# iloc + 行号,可同时指定列,行列都使用切片编号
# 使用切片时不包含`end`
frame.iloc[1] # 第一行
frame.iloc[:10]
frame.iloc[:, 0] # 第一列
frame.iloc[:10, 5:]

# loc + 索引,可同时指定列,行列都使用索引
# 使用切片时包含`end`
# 类似numpy操作,其中`start:end`是包含`end`的,且取值不一定是整数
frame.loc['row_index']
frame.loc[['row_index1', 'row_index_2']]
frame.loc[:, 'column_index']
frame.loc[:, ['column_index_1', 'column_index_2']]
frame.loc[['row_index1', 'row_index_2'], ['column_index_1', 'column_index_2']]
  • 查询行数: len(df.index), len(df)
  • 查询前/后几行:df.head(i), df.tail(i)
  • 筛选获得符合条件的行
  • 本质就是一些 Series 的判断语句
  • 可以通过 query 实现一些复杂功能,但我没细看过
# 数值比较大小
df = df[df.age > 18]

# 多个条件可通过 | 或 & 连接
# 注意优先级,每个条件最好通过 () 包裹
df = df[(df.age < 18 ) & (df.gender == 'male')]

# not 操作
df = df[~df['flag']]

# in 操作
df = df[df.company.isin(companies)]
  • 将行随机转换为几个子集(切割dataframe)
# 如果只要随机获取一定比例的样本,可以通过 sample
df.sample(frac=0.5)

# 假设要把df转换为train/val/test,分别是0.8/0.1/0.1的比例,则
num_train = int(len(df)*0.8)
num_val = int(len(df)*0.1)
num_test = len(df) - num_train - num_val
df = df.sample(frac=1.0) # shuffle
train_df = df[:num_train]
val_df = df[num_train:(num_train+num_val)]
test_df = df[:-num_test]
# 通过loc指定新的行索引,增加行
# 这种方式可以不管类型,直接赋值
df.loc['new_raw_index'] = 1 # 不管数据类型,行所有的数据都为1
df.loc['new_raw_index'] = {'a': 1, 'b': 'two'} # 必须指定所有列,否则报错

# append
# 传入的必须是Series对象、字典、字典列表
df = df.append({'a': 5}, ignore_index=True)
  • 遍历行
for row in df.iterrows():
    # row 是个元组,包含快两个数据
    # row[0] 应该是行索引
    # row[1] 是个 Series 对象,可以直接通过 row[1].column_name 来获取数据
    pass
  • 根据行id删除行:df.drop([0, 5])
  • 删除重复行:df.drop_duplicates([0, 5]),其中选择的是列名,即 df.columns 中内容
  • group by操作
  • 功能:按照某行/列数据进行汇总。
  • 主要参数包括:by,选择行index或列index;axis,0 按行汇总(默认),1 按列汇总;as_index,是否将 by 操作的行/列作为新DF的index。
  • 执行 apply 后函数输入是对应group的dataframe对象,返回Series数据后可组成新的行/列。

2.4. 列

  • 查列索引/列名称:df.columns
  • 查一列或多列
# 通过字典或属性的方式,获取列对象(Series)
frame2['year']
frame2.year

# 通过icol获取单列(Series)
frame.icol(0)

# 获取多列(DataFrame)
frame[['w']]
frame[['w', 'z']]
  • 可以通过赋值直接修改列的值。要求是标量,或长度与DataFrame匹配。
  • 对不存在的列赋值,会创建列。
  • 删除列通过del实现,如del frame2['tes']
  • 通过 drop 实现,如 df.drop([1, 2], axis=1),其中选择的是列名,即 df.columns 中内容。
  • 列数:df[0].count()

2.5. 其他操作

  • 转置,如frame.T
  • 获取行与列:df.shape
  • 替换NAN为0:df..fillna(0)
  • 两个DataFrame拼接成一个:df.concat([df1, df2])

3. 其他

3.1. 读取文件

# 普通读取
df = pd.read_csv(FILE_PATH)

# 默认情况下,认为文件第一行为Header,即列名
# 如果第一行不是列名,则需要设置 header 为None,如下所示
df = pd.read_csv(FILE_PATH, header=None)

# 默认情况下,文件中没有索引(即行名)
# 如果要设置第一列为行名,可以设置 index_col 
df = pd.read_csv(FILE_PATH, index_col=0)

# 如果第一行不是列名,则需要设置 header 为None,如下所示
df = pd.read_csv(FILE_PATH, header=None)

# 分块读取并且遍历,chunksize代表每次读取的行数量
df = pd.read_csv(FILE_PATH, chunksize=1000)
for piece in df:
    # piece 可以作为 DateFrame 操作
    ...

# 读取开头若干行数据,读取前1000行
df = pd.read_csv(FILE_PATH, nrows=1000)

3.2. 写文件

train_df.to_csv('/path/to/target.csv', 
                sep=',', # 分隔符
                na_rep='', # 缺失数据补全
                float_format=None, # C语言格式的浮点数格式,如'%10.5'
                columns=None, # 要保存的列,看到举例使用的是列名
                header=True, # 列名展示,可以是True/False,也可以输入list来指定列名
                index=True, # 是否打印行名
                encoding='utf8', # 编码
               )
# 如果在指定了 float_format 后部分整数也有小数部分,可以先将对应列转换类型,例如
df[['cycle', 'passs', 'ip']]=df[['cycle', 'passs', 'ip']].astype(int64)