python机器学习基础笔记之pandas

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]
'''


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

万物琴弦光锥之外

给个0.1,恭喜老板发财

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值