Pandas
- pandas 中的数据导入以及常用操作语句
- 创建 数据框dataframe(二维数据框)
- 描述数据
- 选择元素,切片处理
- 选择行,based on conditionals
- 替换数值value
- 重命名 列(rename)
- statistics
- Finding Unique Values
- 缺失值的处理
- 删除列(drop([ ,] , axis =1))
- 删除行(drop([,] , axis =0 ))
- 舍弃重复行(drop_duplicates(subset = []))
- grouping
- 行加时间戳
- Looping Over a Column
- apply函数在列
- Applying a Function to Groups
- 连接数据框(concatenate)
- 合并数据框(merge(A,B, on='?',how = ?))
- pandas知识
- 读取剪切板
- 读取字符串数据和字节流数据
- 如果csv文件没有列名,只有数据,然后你读数据,并且自己定义列名
- 如果你想读取某几列
- 读取数据中有重复列
- 时间解析
- 读取数据的编码
- 文件对象的读取
- 输出为压缩文件
- 导入df到不同的Excel 的sheet
- 导出成markdown
- 索引重置
- 索引属性
- 索引方法
- 索引重命名
- df统计函数
- s专有
- diff 和 shift 和rank
- 类似于字典的get
- 逻辑筛选
- replace替换值
- 填充值
- rename
- insert
- assign
- 高级筛选
- mask
- 函数应用
- 分组-应用
pandas 中的数据导入以及常用操作语句
首先导入数据:
pd.read_csv
pd.read_excel
pd.read_json
然后粗略查看数据by:
dataframe.head()
dataframe.tail()
# Load library
import pandas as pd
# Create URL
url = 'https://tinyurl.com/titanic-csv'
# Load data as a dataframe
dataframe = pd.read_csv(url)
# Show first 5 rows
dataframe.head(5)
创建 数据框dataframe(二维数据框)
dataframe = pd.DataFrame()
# Load library
import pandas as pd
# Create DataFrame
dataframe = pd.DataFrame()
# Add columns
dataframe['Name'] = ['Jacky Jackson', 'Steven Stevenson']
dataframe['Age'] = [38, 25]
dataframe['Driver'] = [True, False]
# Show DataFrame
dataframe
append新的行——也就是一个observation
ps: pd.Series([ ’ ‘] , index = [’ ']) 一维数据
# Create row
new_person = pd.Series(['Molly Mooney', 40, True], index=['Name','Age','Driver'])
# Append row
dataframe.append(new_person, ignore_index=True)
描述数据
df.describe()
# Show dimensions
dataframe.shape
# Show statistics
dataframe.describe()
选择元素,切片处理
注意:
1.选取行,用 loc选取位置(‘string’),用iloc选取实际index坐标位置.
2.选取列,用df[‘columns’]就行
# Select first row
dataframe.iloc[0]
# Select three rows
dataframe.iloc[1:4]
# Select four rows
dataframe.iloc[:4]
# Set index
dataframe = dataframe.set_index(dataframe['Name'])
# Show row
dataframe.loc['Allen, Miss Elisabeth Walton']
选择行,based on conditionals
!!! 直接dataframe[(条件1) & (条件2)] !!!
# Show top two rows where column 'sex' is 'female'
dataframe[dataframe['Sex'] == 'female'].head(2)
# Filter rows
dataframe[(dataframe['Sex'] == 'female') & (dataframe['Age'] >= 65)]
替换数值value
replace用 list 做参数
replace([‘A’],[‘B’])
replace A with B
# Load library
import pandas as pd
# Create URL
url = 'https://tinyurl.com/titanic-csv'
# Load data
dataframe = pd.read_csv(url)
# Replace values, show two rows
dataframe['Sex'].replace("female", "Woman").head(2)
0 Woman
1 Woman
Name: Sex, dtype: object
# Replace "female" and "male with "Woman" and "Man"
dataframe['Sex'].replace(["female", "male"], ["Woman", "Man"]).head(5)
0 Woman
1 Woman
2 Man
3 Woman
4 Man
Name: Sex, dtype: object
# Replace values, show two rows
dataframe.replace(1, "One").head(2)
重命名 列(rename)
rename with 字典作为参数!
# Load library
import pandas as pd
# Create URL
url = 'https://tinyurl.com/titanic-csv'
# Load data
dataframe = pd.read_csv(url)
# Rename column, show two rows
dataframe.rename(columns={'PClass': 'Passenger Class'}).head(2)
# Rename columns, show two rows
dataframe.rename(columns={'PClass': 'Passenger Class', 'Sex': 'Gender'}).head(2)
如果要重命名所有的列:
# Load library
import collections
# Create dictionary
column_names = collections.defaultdict(str)
# Create keys
for name in dataframe.columns:
column_names[name]
# Show dictionary
column_names
defaultdict(str,
{'Age': '',
'Name': '',
'PClass': '',
'Sex': '',
'SexCode': '',
'Survived': ''})
statistics
# Calculate statistics
print('Maximum:', dataframe['Age'].max())
print('Minimum:', dataframe['Age'].min())
print('Mean:', dataframe['Age'].mean())
print('Sum:', dataframe['Age'].sum())
print('Count:', dataframe['Age'].count())
# Show counts
dataframe.count()
Name 1313
PClass 1313
Age 756
Sex 1313
Survived 1313
SexCode 1313
dtype: int64
Finding Unique Values
# Select unique values
dataframe['Sex'].unique()
# Show counts
dataframe['Sex'].value_counts()
# Show counts
dataframe['PClass'].value_counts()
3rd 711
1st 322
2nd 279
* 1
Name: PClass, dtype: int64
# While almost all passengers belong to one of three classes as expected, a single pas‐
senger has the class *.
Show number of unique values
dataframe['PClass'].nunique()
缺失值的处理
三种方式,参考后面的笔记。
## Select missing values, show two rows
dataframe[dataframe['Age'].isnull()].head(2)
# Replace values with NaN
dataframe['Sex'] = dataframe['Sex'].replace('male', np.nan)
# Load data, set missing values
dataframe = pd.read_csv(url, na_values=[np.nan, 'NONE', -999])
删除列(drop([ ,] , axis =1))
==I recommend treating DataFrames as immutable objects. ==
dataframe.drop('Age', axis=1).head(2)
# Drop columns
dataframe.drop(['Age', 'Sex'], axis=1).head(2)
# Create a new DataFrame
dataframe_name_dropped = dataframe.drop(dataframe.columns[0], axis=1)
删除行(drop([,] , axis =0 ))
第二种方式有点奇妙
df.drop([0, 1], axis=0)
dataframe[dataframe['Name'] != 'Allison, Miss Helen Loraine'].head(2)
# 删除Allison, Miss Helen Loraine
# Delete row, show first two rows of output
dataframe[dataframe.index != 0].head(2)
舍弃重复行(drop_duplicates(subset = []))
drop_duplicates 默认要完美across所有的列,如果你只是写一个列名,那就用subset,而且用完后只能显示重复的行,要用keep = ‘last’,才会最终达到目的。
perfectly across all columns.
# Drop duplicates, show first two rows of output
dataframe.drop_duplicates().head(2)
# Drop duplicates
dataframe.drop_duplicates(subset=['Sex'])
# Drop duplicates
dataframe.drop_duplicates(subset=['Sex'], keep='last')
grouping
groupby()后面必须要计算方式:groupby(‘happy’)[‘name’].count()
# Group rows by the values of the column 'Sex', calculate mean
# of each group
dataframe.groupby('Sex').mean()
# Group rows, count rows
dataframe.groupby('Survived')['Name'].count()
# Group rows, calculate mean
dataframe.groupby(['Sex','Survived'])['Age'].mean()
行加时间戳
#举例子
# Create date range
ime_index = pd.date_range('06/06/2017', periods=100000, freq='30S')
# Create DataFrame
dataframe = pd.DataFrame(index=time_index)
# Create column of random values
dataframe['Sale_Amount'] = np.random.randint(1, 10, 100000)
# Group rows by week, calculate sum per week
dataframe.resample('W').sum()
Looping Over a Column
# Show first two names uppercased
[name.upper() for name in dataframe['Name'][0:2]]
['ALLEN, MISS ELISABETH WALTON', 'ALLISON, MISS HELEN LORAINE']
apply函数在列
Use apply to apply a built-in or custom function on every element in a column:
# Create function
def uppercase(x):
return x.upper()
# Apply function, show two rows
dataframe['Name'].apply(uppercase)[0:2]
0 ALLEN, MISS ELISABETH WALTON
1 ALLISON, MISS HELEN LORAINE
Name: Name, dtype: object
Applying a Function to Groups
apply( function)
# Group rows, apply function to groups
dataframe.groupby('Sex').apply(lambda x: x.count())
连接数据框(concatenate)
concat([ A , B ] ,axis = ?)
# Concatenate DataFrames by rows
pd.concat([dataframe_a, dataframe_b], axis=0)
#You can use axis=1 to concatenate along the #column axis:
# Concatenate DataFrames by columns
pd.concat([dataframe_a, dataframe_b], axis=1)
合并数据框(merge(A,B, on=‘?’,how = ?))
pd.merge(dataframe_employees, dataframe_sales, on='employee_id')
# Merge DataFrames
pd.merge(dataframe_employees, dataframe_sales, on='employee_id', how='outer')
# Merge DataFrames
pd.merge(dataframe_employees, dataframe_sales, on='employee_id', how='left')
# Merge DataFrames
pd.merge(dataframe_employees,
dataframe_sales,
left_on='employee_id',
right_on='employee_id')
What is the left and right DataFrame? The simple answer is that the left DataFrame is
the first one we specified in merge and the right DataFrame is the second one. This
language comes up again in the next sets of parameters we will need.
pandas知识
Pandas数据类型是指某一列里所有数据的共性,如果全是数字,那么就是数字型;如果其中有一个不是数据,那么就不是数字型了。我们知道Pandas里的一列可以由NumPy数组组成,事实上大多NumPy的数据类型就是Pandas的类型,Pandas也有自己特有的数据类型。
Pandas提供了以下常见的数据类型,默认的数据类型是int64和float64,文字类型是object。
float
int
bool
datetime64[ns]
datetime64[ns, tz]
timedelta64[ns]
timedelta[ns]
category
object
string
pd.read_csv('https://www.gairuo.com/file/data/dataset/GDP-China.csv') # CSV文件可以存储在网络上,通过URL来访问和读取
基本上,read_XXX都支持直接从url读取!!!
读取剪切板
剪贴板(Clipboard)是操作系统级的一个暂存数据的地方,它保存在内存中,可以在不同软件之间传递,非常方便。Pandas支持读取剪贴板中的结构化数据,这就意味着我们不用将数据保存成文件,而可以直接从网页、Excel等文件中复制,然后从操作系统的剪贴板中读取,非常方便
'''
x y z
a 1 2 3
b 4 5 6
c 7 8 9
'''
# 复制上边的数据,然后直接赋值
cdf = pd.read_clipboard()
读取字符串数据和字节流数据
from io import StringIO
data = ('col1,col2,col3\n'
'a,b,1\n'
'a,b,2\n'
'c,d,3')
pd.read_csv(StringIO(data))
pd.read_csv(StringIO(data), dtype=object)
from io import BytesIO
data = (b'word,length\n'
b'Tr\xc3\xa4umen,7\n'
b'Gr\xc3\xbc\xc3\x9fe,5')
pd.read_csv(BytesIO(data))
如果csv文件没有列名,只有数据,然后你读数据,并且自己定义列名
pd.read_csv(data, names=['列1', '列2']) # 指定列名列表
pd.read_csv(data, names=['列1', '列2'], header=None)
如果你想读取某几列
# 支持类似列表的序列和可调用对象
# 读取部分列
pd.read_csv(data, usecols=[0,4,3]) # 按索引只读取指定列,与顺序无关
pd.read_csv(data, usecols=['列1', '列5']) # 按列名,列名必须存在
# 指定列顺序,其实是df的筛选功能
pd.read_csv(data, usecols=['列1', '列5'])[['列5', '列1']]
# 以下用callable方式可以巧妙指定顺序,in后面的是我们要的顺序
pd.read_csv(data, usecols=lambda x: x.upper() in ['COL3', 'COL1'])
读取数据中有重复列
# 布尔型,默认为True
data = 'a,b,a\n0,1,2\n3,4,5'
pd.read_csv(StringIO(data), mangle_dupe_cols=True)
# 表头为a b a.1
# False会报ValueError错误
时间解析
import pandas as pd
# 布尔型、整型组成的列表、列表组成的列表或者字典,默认为False
pd.read_csv(data, parse_dates=True) # 自动解析日期时间格式
pd.read_csv(data, parse_dates=['年份']) # 指定日期时间字段进行解析
# 将第1、4列合并解析成名为“时间”的时间类型列
pd.read_csv(data, parse_dates={'时间':[1,4]})
读取数据的编码
# 字符型,默认为None
pd.read_csv('gairuo.csv', encoding='utf8')
pd.read_csv("gairuo.csv",encoding="gb2312") # 常见中文
文件对象的读取
# 布尔型,默认为False
pd.read_csv(data, iterator=True) # 1
# 整型,默认为None
pd.read_csv(data, chunksize=100000) #2
# 分块处理大文件
df_iterator = pd.read_csv(file, chunksize=50000) #3
def process_dataframe(df):
pass
return processed_df
for index,df_tmp in enumerate(df_iterator):
df_processed = process_dataframe(df_tmp)
if index > 0:
df_processed.to_csv(path)
else:
df_processed.to_csv(path, mode='a', header=False)
# 可选值有'infer'、'gzip'、'bz2'、'zip'、'xz'和None,默认为'infer'
pd.read_csv('sample.tar.gz', compression='gzip') #4
输出为压缩文件
# 创建一个包含out.csv的压缩文件out.zip
compression_opts = dict(method='zip',
archive_name='out.csv')
df.to_csv('out.zip', index=False,
compression=compression_opts)
导入df到不同的Excel 的sheet
# 将多个df分不同sheet导入一个Excel文件中
with pd.ExcelWriter('path_to_file.xlsx') as writer:
df1.to_excel(writer, sheet_name='Sheet1')
df2.to_excel(writer, sheet_name='Sheet2')
导出成markdown
print(cdf.to_markdown())
'''
| | x | y | z |
|:---|----:|----:|----:|
| a | 1 | 2 | 3 |
| b | 4 | 5 | 6 |
| c | 7 | 8 | 9 |
'''
索引重置
df.reset_index() # 清除索引
df.set_index('month').reset_index() # 相当于什么也没做
# 删除原索引,month列没了
df.set_index('month').reset_index(drop=True)
df2.reset_index(inplace=True) # 覆盖使生效
# year一级索引取消
df.set_index(['month', 'year']).reset_index(level=1)
df2.reset_index(level='class') # 同上,使用层级索引名
df.reset_index(level='class', col_level=1) # 列索引
# 不存在层级名称的填入指定名称
df.reset_index(level='class', col_level=1, col_fill='species')
索引属性
# 常用属性
df.index.name # 名称
df.index.array # array数组
df.index.dtype # 数据类型
df.index.shape # 形状
df.index.size # 元素数量
df.index.values # array数组
# 其他,不常用
df.index.empty # 是否为空
df.index.is_unique # 是否不重复
df.index.names # 名称列表
df.index.is_all_dates # 是否全是日期时间
df.index.has_duplicates # 是否有重复值
df.index.values # 索引的值array
索引方法
# 常用方法
df.index.astype('int64') # 转换类型
df.index.isin() # 是否存在,见下方示例
df.index.rename('number') # 修改索引名称
df.index.nunique() # 不重复值的数量
df.index.sort_values(ascending=False,) # 排序,倒序
df.index.map(lambda x:x+'_') # map函数处理
df.index.str.replace('_', '') # str替换
df.index.str.split('_') # 分隔
df.index.to_list() # 转为列表
df.index.to_frame(index=False, name='a') # 转成DataFrame
df.index.to_series() # 转为series
df.index.to_numpy() # 转为numpy
df.index.unique() # 去重
df.index.value_counts() # 去重及计数
df.index.where(df.index=='a') # 筛选
df.index.rename('grade', inplace=False) # 重命名索引
df.index.rename(['species', 'year']) # 多层,重命名索引
df.index.max() # 最大值
df.index.argmax() # 最大索引值
df.index.any()
df.index.all()
df.index.T # 转置,在多层索引里很有用
索引重命名
s.rename_axis("student_name") # 索引重命名
df.rename_axis(["dow", "hr"]) # 多层索引修改索引名
df.rename_axis('info', axis="columns") # 修改行索引名
# 修改多层列索引名
df.rename_axis(index={'a': 'A', 'b': 'B'})
# 修改多层列索引名
df.rename_axis(columns={'name': 's_name', 'b': 'B'})
df.rename_axis(columns=str.upper) # 行索引名变大写
df统计函数
df.mean() # 返回所有列的均值
df.mean(1) # 返回所有行的均值,下同
df.corr() # 返回列与列之间的相关系数
df.count() # 返回每一列中的非空值的个数
df.max() # 返回每一列的最大值
df.min() # 返回每一列的最小值
df.abs() # 绝对值
df.median() # 返回每一列的中位数
df.std() # 返回每一列的标准差,贝塞尔校正的样本标准偏差
df.var() # 无偏方差
df.sem() # 平均值的标准误差
df.mode() # 众数
df.prod() # 连乘
df.mad() # 平均绝对偏差
df.cumprod() # 累积连乘,累乘
df.cumsum(axis=0) # 累积连加,累加
df.nunique() # 去重数量,不同值的量
df.idxmax() # 每列最大值的索引名
df.idxmin() # 每列最小值的索引名
df.cummax() # 累积最大值
df.cummin() # 累积最小值
df.skew() # 样本偏度(第三阶)
df.kurt() # 样本峰度(第四阶)
df.quantile() # 样本分位数(不同 % 的值)
s专有
# 不重复的值及数量
s.value_counts()
s.value_counts(normalize=True) # 重复值的频率
s.value_counts(sort=False) # 不按频率排序
s.unique() # 去重的值 array
s.is_unique # 是否有重复
# 最大最小值
s.nlargest() # 最大的前5个
s.nlargest(15) # 最大的前15个
s.nsmallest() # 最小的前5个
s.nsmallest(15) # 最小的前15个
s.pct_change() # 计算与前一行的变化百分比
s.pct_change(periods=2) # 前两行
s1.cov(s2) # 两个序列的协方差
diff 和 shift 和rank
# 整体下移一行,最顶的一行为NaN
df.shift()
df.shift(3) # 移三行
# 整体上移一行,最底的一行为NaN
df.Q1.head().shift(-1)
# 向右移动一位
df.shift(axis=1)
df.shift(3, axis=1) # 移三位
# 向左移动一位
df.shift(-1, axis=1)
# 实现了df.Q1.diff()
df.Q1 - df.Q1.shift()
# 排名,将值变了序号
df.head().rank()
'''
name team Q1 Q2 Q3 Q4
0 4.0 5.0 4.0 1.0 2.0 2.0
1 2.0 2.5 1.0 2.0 3.0 1.0
2 1.0 1.0 2.0 4.0 1.0 4.0
3 3.0 2.5 5.0 5.0 5.0 3.0
4 5.0 4.0 3.0 3.0 4.0 5.0
'''
# 横向排名
df.head().rank(axis=1)
'''
Q1 Q2 Q3 Q4
0 4.0 1.0 2.0 3.0
1 1.0 2.5 2.5 4.0
2 2.0 3.0 1.0 4.0
3 3.0 4.0 1.0 2.0
4 3.0 1.0 2.0 4.0
'''
如果遇到空值,可以传入na_option='bottom',把空值放在最后,值为top放在前面。
类似于字典的get
df.get('name', 0) # 是name列
df.get('nameXXX', 0) # 0,返回默认值
s.get(3, 0) # 93,Series传索引返回具体值
df.name.get(99, 0) # 'Ben'
逻辑筛选
# Q1成绩不小于60分,并且是C组成员
~(df.Q1 < 60) & (df['team'] == 'C')
'''
0 False
1 False
2 False
3 True
4 False
...
95 False
96 False
97 True
98 False
99 False
Length: 100, dtype: bool
'''
df[df['Q1'] == 8] # Q1等于8
df[~(df['Q1'] == 8)] # 不等于8
df[df.name == 'Ben'] # 姓名为Ben
df[df.Q1 > df.Q2]
# 表达式与切片一致
df.loc[df['Q1'] > 90, 'Q1':] # Q1大于90,只显示Q1
df.loc[(df.Q1 > 80) & (df.Q2 < 15)] # and关系
df.loc[(df.Q1 > 90) | (df.Q2 < 90)] # or关系
df.loc[df['Q1'] == 8] # 等于8
df.loc[df.Q1 == 8] # 等于8
df.loc[df['Q1'] > 90, 'Q1':] # Q1大于90,显示Q1及其后所有列
需要注意的是在进行或(|)、与(&)、非(~)运算时,各个独立逻辑表达式需要用括号括起来
# Q1、Q2成绩全为超过80分的
df[(df.loc[:,['Q1','Q2']] > 80).all(1)]
# Q1、Q2成绩至少有一个超过80分的
df[(df.loc[:,['Q1','Q2']] > 80).any(1)]
df[lambda df: df['Q1'] == 8] # Q1为8的
df.loc[lambda df: df.Q1 == 8, 'Q1':'Q2'] # Q1为8的,显示 Q1、Q2
df.loc[:, lambda df: df.columns.str.len()==4] # 由真假值组成的序列
df.loc[:, lambda df: [i for i in df.columns if 'Q' in i]] # 列名列表
df.iloc[:3, lambda df: df.columns.str.len()==2] # 由真假值组成的序列
df.query('Q1 > Q2 > 90') # 直接写类型SQL where语句
df.query('Q1 + Q2 > 180')
df.query('Q1 == Q2')
df.query('(Q1<50) & (Q2>40) and (Q3>90)')
df.query('Q1 > Q2 > Q3 > Q4')
df.query('team != "C"')
df.query('team not in ("E","A","B")')
# 对于名称中带有空格的列,可以使用反引号引起来
df.query('B == `team name`')
# 支持传入变量,如大于平均分40分的
a = df.Q1.mean()
df.query('Q1 > @a+40')
df.query('Q1 > `Q2`+@a')
df.filter(items=['Q1', 'Q2']) # 选择两列
df.filter(regex='Q', axis=1) # 列名包含Q的列
df.filter(regex='e$', axis=1) # 以e结尾的列
df.filter(regex='1$', axis=0) # 正则,索引名以1结尾
df.filter(like='2', axis=0) # 索引中有2的
# 索引中以2开头、列名有Q的
df.filter(regex='^2', axis=0).filter(like='Q', axis=1)
df.select_dtypes(include=['float64']) # 选择float64型数据
df.select_dtypes(include='bool')
df.select_dtypes(include=['number']) # 只取数字型
df.select_dtypes(exclude=['int']) # 排除int类型
df.select_dtypes(exclude=['datetime64'])
replace替换值
s.replace(0, 5) # 将列数据中的0换为5
df.replace(0, 5) # 将数据中的所有0换为5
df.replace([0, 1, 2, 3], 4) # 将0~3全换成4
df.replace([0, 1, 2, 3], [4, 3, 2, 1]) # 对应修改
# {'pad', 'ffill', 'bfill', None} 试试
s.replace([1, 2], method='bfill') # 向下填充
df.replace({0: 10, 1: 100}) # 字典对应修改
df.replace({'Q1': 0, 'Q2': 5}, 100) # 将指定字段的指定值修改为100
df.replace({'Q1': {0: 100, 4: 400}}) # 将指定列里的指定值替换为另一个指定的值
# 使用正则表达式
df.replace(to_replace=r'^ba.$', value='new', regex=True)
df.replace({'A': r'^ba.$'}, {'A': 'new'}, regex=True)
df.replace(regex={r'^ba.$': 'new', 'foo': 'xyz'})
df.replace(regex=[r'^ba.$', 'foo'], value='new')
填充值
df.fillna(0) # 将空值全修改为0
# {'backfill', 'bfill', 'pad', 'ffill', None}, 默认为None
df.fillna(method='ffill') # 将空值都修改为其前一个值
values = {'A': 0, 'B': 1, 'C': 2, 'D': 3}
df.fillna(value=values) # 为各列填充不同的值
df.fillna(value=values, limit=1) # 只替换第一个
rename
df.rename(columns={"Q1": "a", "Q2": "b"}) # 对表头进行修改
df.rename(index={0: "x", 1: "y", 2: "z"}) # 对索引进行修改
df.rename(index=str) # 对类型进行修改
df.rename(str.lower, axis='columns') # 传索引类型
df.rename({1: 2, 2: 4}, axis='index')
# 对索引名进行修改
s.rename_axis("animal")
df.rename_axis("animal") # 默认是列索引
df.rename_axis("limbs", axis="columns") # 指定行索引
# 索引为多层索引时可以将type修改为class
df.rename_axis(index={'type': 'class'})
# 可以用set_axis进行设置修改
s.set_axis(['a', 'b', 'c'], axis=0)
df.set_axis(['I', 'II'], axis='columns')
df.set_axis(['i', 'ii'], axis='columns', inplace=True)
insert
# 在第三列的位置上插入新列total列,值为每行的总成绩
df.insert(2, 'total', df.sum(1))
'''
name team total Q1 Q2 Q3 Q4
0 Liver E 198 89 21 24 64
1 Arry C 167 36 37 37 57
2 Ack A 219 57 60 18 84
3 Eorge C 338 93 96 71 78
4 Oah D 261 65 49 61 86
.. ... ... ... .. .. .. ..
95 Gabriel C 268 48 59 87 74
96 Austin7 C 125 21 31 30 43
97 Lincoln4 C 212 98 93 1 20
98 Eli E 234 11 74 58 91
99 Ben E 179 21 43 41 74
[100 rows x 7 columns]
'''
assign
# 增加两列
df.assign(total=df.sum(1), Q=100)
df.assign(total=df.sum(1)).assign(Q=100) # 效果同上
'''
name team Q1 Q2 Q3 Q4 total Q
0 Liver E 89 21 24 64 198 100
1 Arry C 36 37 37 57 167 100
2 Ack A 57 60 18 84 219 100
3 Eorge C 93 96 71 78 338 100
4 Oah D 65 49 61 86 261 100
.. ... ... .. .. .. .. ... ...
95 Gabriel C 48 59 87 74 268 100
96 Austin7 C 21 31 30 43 125 100
97 Lincoln4 C 98 93 1 20 212 100
98 Eli E 11 74 58 91 234 100
99 Ben E 21 43 41 74 179 100
'''
# 使用了链式方法
(
df.assign(total=df.sum(1)) # 总成绩
.assign(Q=100) # 目标满分值
.assign(name_len=df.name.str.len()) # 姓名长度
.assign(avg=df.mean(1)) # 平均值
.assign(avg2=lambda d: d.total/4) # 平均值2
)
'''
name team Q1 Q2 Q3 Q4 total Q name_len avg avg2
0 Liver E 89 21 24 64 198 100 5 49.50 49.50
1 Arry C 36 37 37 57 167 100 4 41.75 41.75
2 Ack A 57 60 18 84 219 100 3 54.75 54.75
3 Eorge C 93 96 71 78 338 100 5 84.50 84.50
4 Oah D 65 49 61 86 261 100 3 65.25 65.25
.. ... ... .. .. .. .. ... ... ... ... ...
95 Gabriel C 48 59 87 74 268 100 7 67.00 67.00
96 Austin7 C 21 31 30 43 125 100 7 31.25 31.25
97 Lincoln4 C 98 93 1 20 212 100 8 53.00 53.00
98 Eli E 11 74 58 91 234 100 3 58.50 58.50
99 Ben E 21 43 41 74 179 100 3 44.75 44.75
[100 rows x 11 columns]
'''
以上是使用了链式方法的典型代码形式,后期会以这种风格进行代码编写。特别要说明的是avg2列的计算过程,因为df实际是没有total这一列的,如果我们需要使用total列,就需要用lambda来调用。lambda中第一个变量d是代码执行到本行前的DataFrame内容,可以认为是一个虚拟的DataFrame实体,然后用变量d使用这个DataFrame的数据。作为变量名,d可以替换为其他任意合法的名称,但为了代码可读性,建议使用d,代表它是一个DataFrame。如果是Series,建议使用s。
df.assign(Q5=[100]*100) # 新增加一列Q5
df = df.assign(Q5=[100]*100) # 赋值生效
df.assign(Q6=df.Q2/df.Q1) # 计算并增加Q6
df.assign(Q7=lambda d: d.Q1 * 9 / 5 + 32) # 使用lambda
# 添加一列,值为表达式结果:True或False
df.assign(tag=df.Q1>df.Q2)
# 比较计算,True为1,False为0
df.assign(tag=(df.Q1>df.Q2).astype(int))
# 映射文案
df.assign(tag=(df.Q1>60).map({True:'及格',False:'不及格'}))
# 增加多个
df.assign(Q8=lambda d: d.Q1*5,
Q9=lambda d: d.Q8+1) # Q8没有生效,不能直接用df.Q8
高级筛选
df.where()中可以传入一个布尔表达式、布尔值的Series/DataFrame、序列或者可调用的对象,然后与原数据做对比,返回一个行索引与列索引与原数据相同的数据,且在满足条件的位置保留原值,在不满足条件的位置填充NaN
# 大于等于60分的显示成绩,小于的显示“不及格”
df.where(df>=60, '不及格')
'''
Q1 Q2 Q3 Q4
0 89 不及格 不及格 64
1 不及格 不及格 不及格 不及格
2 不及格 60 不及格 84
3 93 96 71 78
4 65 不及格 61 86
.. ... ... ... ...
95 不及格 不及格 87 74
96 不及格 不及格 不及格 不及格
97 98 93 不及格 不及格
98 不及格 74 不及格 91
99 不及格 不及格 不及格 74
[100 rows x 4 columns]
'''
# c 定义一个数是否为偶数的表达式
c = df%2 == 0
# 传入c, 为偶数时显示原值减去20后的相反数
df.where(~c, -(df-20))
'''
Q1 Q2 Q3 Q4
0 89 21 -4 -44
1 -16 37 37 57
2 57 -40 2 -64
3 93 -76 71 -58
4 65 49 61 -66
.. .. .. .. ..
95 -28 59 87 -54
96 21 31 -10 43
97 -78 93 1 0
98 11 -54 -38 91
99 21 43 41 -54
[100 rows x 4 columns]
'''
df.where()方法可以将满足条件的值筛选出来,将不满足的值替换为另一个值,但无法对满足条件的值进行替换,而np.where()就实现了这种功能,达到SQL中if(条件,条件为真的值,条件为假的值)的效果
# 小于60分为不及格
np.where(df>=60, '合格', '不合格')
'''
array([['合格', '不合格', '不合格', '合格'],
['不合格', '不合格', '不合格', '不合格'],
['不合格', '合格', '不合格', '合格'],
['合格', '合格', '合格', '合格'],
['合格', '不合格', '合格', '合格'],
....
['不合格', '不合格', '不合格', '不合格'],
['合格', '合格', '不合格', '不合格'],
['不合格', '合格', '不合格', '合格'],
['不合格', '不合格', '不合格', '合格']], dtype='<U3')
'''
# 让df.where()中的条件为假,从而应用np.where()的计算结果
df.where(df==9999999, np.where(df>=60, '合格', '不合格'))
'''
Q1 Q2 Q3 Q4
0 合格 不合格 不合格 合格
1 不合格 不合格 不合格 不合格
2 不合格 合格 不合格 合格
3 合格 合格 合格 合格
4 合格 不合格 合格 合格
.. ... ... ... ...
95 不合格 不合格 合格 合格
96 不合格 不合格 不合格 不合格
97 合格 合格 不合格 不合格
98 不合格 合格 不合格 合格
99 不合格 不合格 不合格 合格
[100 rows x 4 columns]
'''
mask
df.mask()的用法和df.where()基本相同,唯一的区别是df.mask()将满足条件的位置填充为NaN。
# 符合条件的为NaN
df.mask(s > 80)
'''
Q1 Q2 Q3 Q4
0 NaN NaN NaN NaN
1 36.0 37.0 37.0 57.0
2 57.0 60.0 18.0 84.0
3 NaN NaN NaN NaN
4 65.0 49.0 61.0 86.0
.. ... ... ... ...
95 48.0 59.0 87.0 74.0
96 21.0 31.0 30.0 43.0
97 NaN NaN NaN NaN
98 11.0 74.0 58.0 91.0
99 21.0 43.0 41.0 74.0
[100 rows x 4 columns]
'''
# 对满足条件的位置指定填充值
df.Q1.mask(s > 80, '优秀')
'''
0 优秀
1 36
2 57
3 优秀
4 65
..
95 48
96 21
97 优秀
98 11
99 21
Name: Q1, Length: 100, dtype: object
'''
函数应用
pipe():应用在整个DataFrame或Series上。
apply():应用在DataFrame的行或列中,默认为列。
applymap():应用在DataFrame的每个元素中。
map():应用在Series或DataFrame的一列的每个元素中。
分组-应用
# 按team分组对应列并相加
df.groupby('team').sum()
'''
Q1 Q2 Q3 Q4
team
A 1066 639 875 783
B 975 1218 1202 1136
C 1056 1194 1068 1127
D 860 1191 1241 1199
E 963 1013 881 1033
'''
# 对不同列使用不同的计算方法
df.groupby('team').agg({'Q1': sum, # 总和
'Q2': 'count', # 总数
'Q3':'mean', # 平均
'Q4': max}) # 最大值
'''
Q1 Q2 Q3 Q4
team
A 1066 17 51.470588 97
B 975 22 54.636364 99
C 1056 22 48.545455 98
D 860 19 65.315789 99
E 963 20 44.050000 98
'''
# 对同一列使用不同的计算方法
df.groupby('team').agg({'Q1': [sum, 'std', max], # 使用三个方法
'Q2': 'count', # 总数
'Q3':'mean', # 平均
'Q4': max}) # 最大值
'''
Q1 Q2 Q3 Q4
sum std max count mean max
team
A 1066 24.155136 96 17 51.470588 97
B 975 32.607896 97 22 54.636364 99
C 1056 31.000768 98 22 48.545455 98
D 860 25.886166 80 19 65.315789 99
E 963 33.242767 97 20 44.050000 98
'''
# 对Series df.Q1按team分组,求和
df.Q1.groupby(df.team).sum()
'''
team
A 1066
B 975
C 1056
D 860
E 963
Name: Q1, dtype: int64
'''
# 分组
grouped = df.groupby('team')
# 查看D组
grouped.get_group('D')
'''
name team Q1 Q2 Q3 Q4
4 Oah D 65 49 61 86
8 Reddie D 64 93 57 72
21 Ethan D 79 45 89 88
23 Mason D 80 96 26 49
27 Finley D 62 73 84 68
44 Benjamin D 15 88 52 25
48 Louie D 24 84 54 11
49 Carter7 D 57 52 77 50
52 Bobby1 D 50 55 60 59
57 Albie1 D 79 82 56 96
59 Luca D 5 40 91 83
...
'''
# 索引值是否为偶数,分成两组
df.groupby(lambda x:x%2==0).sum()
df.groupby(df.index%2==0).sum() # 同上
'''
Q1 Q2 Q3 Q4
False 2322 2449 2823 2699
True 2598 2806 2444 2579
'''
# 列名包含Q的分成一组
df.groupby(lambda x:'Q' in x, axis=1).sum()
'''
False True
0 LiverE 198
1 ArryC 167
2 AckA 219
3 EorgeC 338
4 OahD 261
.. ... ...
95 GabrielC 268
96 Austin7C 125
97 Lincoln4C 212
98 EliE 234
99 BenE 179
[100 rows x 2 columns]
'''
# 按索引奇偶行分为True和False两组
df.groupby(df.index%2==0) # 同上例
# 按姓名首字母分组
df.groupby(df.name.str[0])
# 按A及B、其他团队分组
df.groupby(df.team.isin(['A','B']))
# 按姓名第一个字母和第二个字母分组
df.groupby([df.name.str[0], df.name.str[1]])
# 按日期和小时分组
df.groupby([df.time.date, df.time.hour])
# 按team、姓名首字母是否为元音分组
df.groupby(['team', df.name.apply(get_letter_type)]).sum()
'''
Q1 Q2 Q3 Q4
team name
A 元音 274 197 141 199
辅音 792 442 734 584
B 元音 309 291 269 218
辅音 666 927 933 918
C 元音 473 488 453 464
辅音 583 706 615 663
D 元音 273 333 409 486
辅音 587 858 832 713
E 元音 133 131 138 207
辅音 830 882 743 826
'''
groupby操作后分组字段会成为索引,如果不想让它成为索引,可以使用as_index=False进行设置:
df.groupby('team', as_index=False).sum()
'''
team Q1 Q2 Q3 Q4
0 A 1066 639 875 783
1 B 975 1218 1202 1136
2 C 1056 1194 1068 1127
3 D 860 1191 1241 1199
4 E 963 1013 881 1033
'''
# 按分组将一列输出为列表
df.groupby('team').apply(lambda x: x['name'].to_list())
'''
team
A [Ack, Lfie, Oscar, Joshua, Henry, Lucas, Arthu...
B [Acob, Leo, Logan, Thomas, Harrison, Edward, S...
C [Arry, Eorge, Harlie, Archie, Theo, William, D...
D [Oah, Reddie, Ethan, Mason, Finley, Benjamin, ...
E [Liver, James, Max, Isaac, Teddy, Riley, Josep...
dtype: object
'''
# 查看某个组
df.groupby('team').apply(lambda x: x['name'].to_list()).A
'''
['Ack',
'Lfie',
'Oscar',
'Joshua',
'Henry',
'Lucas',
'Arthur',
'Reggie1',
'Toby',
'Dylan',
'Hugo0',
'Caleb',
'Nathan',
'Blake',
'Stanley',
'Tyler',
'Aaron']
'''
# 各组Q1(为参数)成绩最高的前三个
def first_3(df_, c):
return df_[c].sort_values(ascending=False).head(3)
# 调用函数
df.set_index('name').groupby('team').apply(first_3, 'Q1')
'''
team name
A Aaron 96
Henry 91
Nathan 87
B Elijah 97
Harrison 89
Michael 89
C Lincoln4 98
Eorge 93
Alexander 91
D Mason 80
Albie1 79
Ethan 79
E Max 97
Ryan 92
Liver 89
Name: Q1, dtype: int64
'''
# 通过设置group_keys,可以使分组字段不作为索引
(
df.set_index('name')
.groupby('team', group_keys=False)
.apply(first_3, 'Q1')
)
'''
name
Aaron 96
Henry 91
Nathan 87
Elijah 97
Harrison 89
Michael 89
Lincoln4 98
Eorge 93
Alexander 91
Mason 80
Albie1 79
Ethan 79
Max 97
Ryan 92
Liver 89
Name: Q1, dtype: int64
'''
(
df.groupby('team')
.apply(lambda x: pd.Series({
'Q1_sum' : x['Q1'].sum(),
'Q1_max' : x['Q1'].max(),
'Q2_mean' : x['Q2'].mean(),
'Q4_prodsum' : (x['Q4'] * x['Q4']).sum()
}))
)
# 定义一个函数
def f_mi(x):
d = []
d.append(x['Q1'].sum())
d.append(x['Q2'].max())
d.append(x['Q3'].mean())
d.append((x['Q4'] * x['Q4']).sum())
return pd.Series(d, index=[['Q1', 'Q2', 'Q3', 'Q4'],
['sum', 'max', 'mean', 'prodsum']])
# 使用函数
df.groupby('team').apply(f_mi)
# 输出结果
'''
Q1_sum Q1_max Q2_mean Q4_prodsum
team
A 1066.0 96.0 37.588235 51129.0
B 975.0 97.0 55.363636 76696.0
C 1056.0 98.0 54.272727 68571.0
D 860.0 80.0 62.684211 87473.0
E 963.0 97.0 50.650000 71317.0
'''
# 指定列名,列表是为原列和方法
df.groupby('team').Q1.agg(Mean='mean', Sum='sum')
df.groupby('team').agg(Mean=('Q1', 'mean'), Sum=('Q2', 'sum'))
df.groupby('team').agg(
Q1_max=pd.NamedAgg(column='Q1', aggfunc='max'),
Q2_min=pd.NamedAgg(column='Q2', aggfunc='min')
)
df.groupby('team').agg(**{
'1_max':pd.NamedAgg(column='Q1', aggfunc='max')})
'''
1_max
team
A 96
B 97
C 98
D 80
E 97
'''
# 聚合结果使用函数
# lambda/函数,所有方法都可以用
def max_min(x):
return x.max() - x.min()
# 定义函数
df.groupby('team').Q1.agg(Mean='mean',
Sum='sum',
Diff=lambda x: x.max() - x.min(),
Max_min=max_min
)
# 三个周期一聚合(一分钟一个周期)
df.groupby('a').resample('3T').sum()
# 30秒一分组
df.groupby('a').resample('30S').sum()
# 每月
df.groupby('a').resample('M').sum()
# 以右边时间点为标识
df.groupby('a').resample('3T', closed='right').sum()
# 每组第一个
df.groupby('team').first()
'''
name Q1 Q2 Q3 Q4
team
A Ack 57 60 18 84
B Acob 61 95 94 8
C Arry 36 37 37 57
D Oah 65 49 61 86
E Liver 89 21 24 64
'''
# 每组最后一个
df.groupby('team').last()
'''
name Q1 Q2 Q3 Q4
team
A Aaron 96 75 55 8
B Jamie0 39 97 84 55
C Lincoln4 98 93 1 20
D Aiden 20 31 62 68
E Ben 21 43 41 74
'''
# 二分位数,即中位数
df.groupby('team').median() # 同下
df.groupby('team').quantile()
df.groupby('team').quantile(0.5)
'''
Q1 Q2 Q3 Q4
team
A 64.0 27.0 46.0 40.0
B 48.0 47.5 54.0 51.5
C 46.0 47.0 49.0 44.5
D 50.0 70.0 62.0 68.0
E 48.0 52.5 46.5 49.5
'''
# grouped为全数字列,计算在组内的前后差值
grouped.diff()
'''
Q1 Q2 Q3 Q4
0 NaN NaN NaN NaN
1 NaN NaN NaN NaN
2 NaN NaN NaN NaN
3 57.0 59.0 34.0 21.0
4 NaN NaN NaN NaN
.. ... ... ... ...
95 -14.0 21.0 24.0 28.0
96 -27.0 -28.0 -57.0 -31.0
97 77.0 62.0 -29.0 -23.0
98 -27.0 14.0 27.0 84.0
99 10.0 -31.0 -17.0 -17.0
[100 rows x 4 columns]
'''