三、pandas

不带括号的基本属性

df.index  # 结果是一个Index对象, 可以使用等号重新赋值,如: df.index = ['a', 'b', 'c']
df.columns # 结果是一个Index对象,可以使用等号重新赋值,如: df.columns = ['A', 'B', 'C']
# 在对Index对象操作时,可以直接当list使用,不用特意通过tolist()转成list
data = data[[col for col in data.columns if col not in del_cols]] df.values # 注意不能使用等号重新赋值!!! df.shape 返回元组
df.size 总个数
df.dtypes # 返回布尔值,判断对象是否为空
df.empty

设置不隐藏

np.set_printoptions(threshold=1e6)
pd.set_option('display.max_columns', 1000)
pd.set_option('display.width', 1000)
pd.set_option('display.max_colwidth', 1000) # 列名与数据对齐显示
pd.set_option('display.unicode.ambiguous_as_wide', True)
pd.set_option('display.unicode.east_asian_width', True)

df.info()

df.describe()

print(df.describe())
'''
a b
count 9.000000 5.000000
mean 2.777778 2.200000
std 1.201850 0.273861
min 1.000000 2.000000
25% 2.000000 2.000000
50% 3.000000 2.000000
75% 3.000000 2.500000
max 5.000000 2.500000
'''
print(df.describe(include=['object'])) #显示freq最高的对象
# 或print(df.describe(include=object))
print(df.describe(include='all'))

df.astype

# np.int8, np.int16, np.int32, np.int64 四种数据类型可以使用字符串 'i1', 'i2','i4','i8' 代替
dt1 = np.dtype(np.int8)
dt2 = np.dtype('i8') # np.float32, np.float64
#np.float64占用64个bits,每个字节长度为8,所以64/8,占用8个字节
f = np.array([1, 2, 3, 4, 5], dtype=np.float64) # 在pandas中若不考虑存储空间和方式的问题,可以简单使用int,float,str即可
for col_name in data.columns:
if col_name in float_col_list:
data[col_name] = data[col_name].astype(float)
elif col_name in str_col_list:
data[col_name] = data[col_name].astype(str)
else:
data[col_name] = data[col_name].astype(int)

df.idxmin()/df.idxmax

# 返回某列或某几列最小/最大值所在索引
df[col_name].idxmin()
df.idxmin()

df.sort_index()

asc_sorted_df = unsorted_df.sort_index()
desc_sorted_df = unsorted_df.sort_index(ascending=False)
col_sorted_df = unsorted_df.sort_index(axis=1)

df.sort_values()

注意:若前面没有=,一定要带inplace=True, 否则不起作用

注意:若df本身就是通过切片来的,使用inplace=True可能会有报警,因此最好使用等号重新赋值更新

col1_sorted_df = unsorted_df.sort_values(by='col1')
# 或直接改变原数据
unsorted_df.sort_values(by='col1', inplace=True)
col1_col2_sorted_df = unsorted_df.sort_values(by=['col1', 'col2']) # 实际过程中:若想取到排序之后的第一行行号
df_sort.index[0]
# 或者使用df[col_name].idxmin()或df[col_name].idxmax() # 若想排序之后,去掉原索引名,将行索引号赋值给行索引名,可以使用reset_index(drop=True)
data_gr = data_gr.sort_values(by='count', ascending=False).reset_index(drop=True)

df[col_name].value_counts()

#注意:1,只能用于Series;2.返回一个Series,按照出现频率按多到少排序,index为原value
print(data['a'].value_counts()) # 注意以下方法只适合目标value为0,1类型的数据
# 巧用value_counts()和groupby计算不同...类型...的比率
cp_count = data['cp'].value_counts() # cp为胸痛类型 # 输出为Series
gr_cp_sum = data.groupby('cp')['target'].sum() # target为1表示患病,0表示不患病 # 输出为Series
print('不同胸痛类型的就诊者所患病的比率\n', round(gr_cp_sum / cp_count, 2))

df[col_name].unique() / df[col_name].nunique()

# unique()与np.unique()效果一样,返回去重之后的结果,若原数据中包含NaN, 去重之后结果中也会有

# nunique(): 返回去重之后的元素个数,可以使用参数dropna=False(默认是True)决定是否包含NaN
a.nunique() # 默认dropna=True
a.nunique(dropna=False) # 不过滤NaN # 应用:过滤值全一样的列
data = data.iloc[:, [data[col].nunique() != 1 for col in data.columns]]

df.reindex()与df.reindex_like()与df.rename()与df.reset_index()(重建索引)


# 注意不要被reindex的名字所迷惑,其功能类似于切片,如:取0,2,100行,'A', 'B', 'Z'列;不同之处是,可以是原df中不存在的行或列,生成新的df中,这里行或列为NaN
df_reindexed = df.reindex(index=[0,2,100], columns=['A', 'B', 'Z']) # 若想重建索引,直接给df.index赋值即可
df.index = range(len(df)) df1 = pd.DataFrame(np.random.randn(6,3),columns=['col1','col2','col3'])
df2 = pd.DataFrame(np.random.randn(2,3),columns=['col1','col2','col3'])
df1 = df1.reindex_like(df2) # 必须确保df1和df2列明相同 # df1的行数变成与df2一样 # rename通过字典结构重建,注意:需要重新赋值或使用inplace=True
df1 = df1.rename(columns={'col1':'c1','col2':'c2'},index ={0 :'apple',1 :'banana',2 :'durian'})
# 或
df1.rename(columns={'col1':'c1','col2':'c2'},index ={0 :'apple',1 :'banana',2 :'durian'}, inplace=True) # reset_index() 将旧索引添加为列,并使用新的顺序索引----> 多用于使用多个字段groupBy聚合之后
daily_rental = bikeDf_time.groupby(['year','month','day','weekday','day_type'])['count'].sum().reset_index() # 在多重分组时,若不想生成复合索引,使用参数as_index=False, 即可将分组字段作为列来呈现(与上面效果一样)
daily_rental = bikeDf_time.groupby(['year','month','day','weekday','day_type'],as_index=False)['count'].sum() # 使用reset_index(drop=True)将原索引删除,但不将原索引作为新的列插入数据中,一般用于排序之后
data_gr = data_gr.sort_values(by='count', ascending=False).reset_index(drop=True)

df删除列/se删除列(还有其它的?numpy怎么删?)

# list删除元素(三种方法: remove、del、pop)
li = ['A', 'B', 'C']
li.remove('B')
del li[1]
li.pop(2) # 参数是下标 # numpy删除列(一种方法: delete)
a = np.arange(12).reshape(3, 4)
print('第一个数组:')
print(a)
print('未传递Axis参数。在插入之前输入数组会被展开。')
print(np.delete(a, 5)) # 不会影响原数据a
print('删除第二列:')
print(np.delete(a, 1, axis=1)) # 不会影响原数据a
'''
第一个数组:
[[ 0 1 2 3]
[ 4 5 6 7]
[ 8 9 10 11]]
未传递Axis参数。在插入之前输入数组会被展开。
[ 0 1 2 3 4 6 7 8 9 10 11]
删除第二列:
[[ 0 2 3]
[ 4 6 7]
[ 8 10 11]]
''' # DataFrame删除列(三种方法:drop、del、pop, 后面两种只能一个一个的删)
df.drop('A', axis=1, inplace=True)
df.drop(['A', 'B'], axis=1, inplace=True)
del df['A']
df.pop('A') # Series删除某个index(三种方法:drop、del、pop, 后面两种只能一个一个的删)
se.drop(['A', 'B'], inplace=True) # 注意这里不要带axis参数(只有axis=0,所以不用带)
del se['A']
se.pop('A')

df删除行、重复行

df = df.drop(0)  # 索引名0重复被一并删除

# 根据条件删除行
df.drop(data[data['A4']==0].index, inplace=True) copy = sheet1_shee2_merge.drop_duplicates('业务员编码', inplace=False) # 是直接在原来数据上修改还是保留一个副本 # 统计数据重复
# 结果为series, index为False和True, 值分别为不重复和重复的数量
print('sheet1订单号重复检查:')
print(sheet1Df['订单号'].duplicated().value_counts())
# 注意单词写法不一样:drop_duplicates与duplicated # 所有列的值一样视为重复
print(data.duplicated().value_counts())
data.drop_duplicates(inplace=True) # 过滤某列中重复值所在行
df = pd.DataFrame({'A': [12, 13, 12, 25, 60], 'B': [112, 112, 128, 112, 60]})
df = df[~df['B'].duplicated()] # df['B'].duplicated()是一个布尔类型Series
print(df)
'''
A B
0 12 112
2 12 128
4 60 60
'''

用字典创建series和dateframe的区别

前者:字典的key是创建index

后者:字典的key是创建columns

使用loc和iloc进行切片

# 省略方式取列的方法
df['B'] # 取一列
df[['A', 'B']] # 取多列 # 唯一可以省略方式取行的方法:必须使用冒号(其它方式使用loc或iloc)
df[2:4] # 参数是行索引号,结果为2行(等同于df.iloc[2:4, :])
df['20220806': '20220808'] # 行名,,结果为3行 (等同于df.loc['20220806': '20220808', :])
# 注意:上面行名必须是字符串类型才有这种效果!!!否则就视为使用索引号 # loc方法(注意loc中的参数冒号都是取头又取尾,不管index是不是默认或数值型)
df.loc[:, ['A', 'C']]
df.loc['20220806']
df.loc['20220806', 'A':'C']
df.loc['20220806': '20220808', ['A', 'C']]
df.loc['20220806', ['A', 'C']]
df.loc[['20220806', '20220808'], ['A', 'C']] # iloc方法(行索引和列索引都可以不连续)(注意iloc中的参数冒号都是取头不取尾)
df.iloc[2:4, 0:2]
df.iloc[[2, 4], [0, 2]]
df.iloc[1, 1] df.loc['b':'e'] # 是包含e行的
df.iloc[1:4] # index从1到3,不包含4 # Series与DataFrame类似,不同之处是iloc和loc只有一个参数
se[:2] # 等同于se.iloc[:2]
# 注意若se索引名不是采用默认索引,使用数字很有可能报错,所以下面这样方式不要随便使用!!!
se.loc[:2] # 注意这里的2是行号,取值时是包含2的,若行号与索引号不一致,例如排序之后的,取到的行数不确定

df布尔过滤

布尔过滤的原理:通过布尔型Series中的True对应的index来进行匹配,即同时用到了Series中的index和values

  • 过滤某些行:通过某列的条件判断形成布尔型Series :se,然后再通过df[se]达到条件过滤的目的。其中se的长度与df行数一致,且se.index与df.index一致;(其实df[se]是df.loc[se, :]的简写形式)(也可以通过df.iloc[li, :]来达到目的, 其中li为布尔类型list,长度与行数一致)
  • 过滤某些列:通过某行的条件判断形成布尔型Series :se,然后再通过df.loc[:, se]达到条件过滤的目的。其中se的长度与df的列数一致,且se.index与df.columns一致。(也可以通过df.iloc[:, li]来达到目的, 其中li为布尔类型list, 长度与列数一致)
# 布尔过滤原理的验证
df = pd.DataFrame({'A': [12, 13, 12, 25], 'B': [112, 112, 128, 122]}, index=[0, 2, 3, 4])
se = pd.Series([False, True, False, True]) # 使用默认索引
print(df[se]) # 报错
se = pd.Series([False, True, False, True], index=[0, 2, 3, 4])
print(df[se])
'''
A B
2 13 112
4 25 122
'''
print(df[df.A > 0])  # A列大于0的值
# print(df[df['A'] > 0]) # 也可以这样写
'''
A B C D
2020-01-01 0.105586 -0.173702 0.360643 -1.866179
2020-01-06 2.790227 0.053426 -1.123202 0.573211
''' print(df[(df.A > 0) & (df.B < 0)]) # 多个条件过滤:需用小括号包裹,且只能用& | ~ # 注意这里与df[df.A > 0]的区别
# 注意:若条件判断语句不是对某一列进行判断,返回值不会将不满足行过滤掉
print(df[df > 0]) # 获取所有大于0的值,小于0设为NaN
'''
A B C D
2020-01-01 0.021760 0.467921 NaN 0.442172
2020-01-02 NaN NaN NaN NaN
2020-01-03 NaN NaN NaN 0.421954
2020-01-04 NaN NaN NaN 0.254046
2020-01-05 0.970615 1.234028 1.920165 0.802954
2020-01-06 NaN NaN NaN NaN
2020-01-07 NaN 0.292532 NaN NaN
''' # 经试验,作判断前不需要确保没有空值,两种结果一样
#data_year = data[(data['Year'].notnull()) & (data['Year'] >= 1998) & (data['Year'] <= 2008)]
data_year = data[(data['Year'] >= 1998) & (data['Year'] <= 2008)]
# 也可以使用between
data_year = data[data['Year'].between(1998, 2008)]
# 若要排除两头边界,即大于1998且小于2008, 加上参数inclusive=False
data_year = data[data['Year'].between(1998, 2008, inclusive=False)] # 使用isin()方法进行是否在列表中的过滤
df['E'] = ['one', 'one', 'two', 'three', 'four', 'three', 'two']
print(df[df['E'].isin(['two', 'four'])])
# isin()参数也可是Series
# isin()没有isnotin()这样表达,只能通过前面加~来实现
df_normal = data[~data['target'].isin(df_except['target'])] # 过滤某列中重复值所在行
df = df[~df['B'].duplicated()] # 字符串类型的模糊查询
copy2 = copy.loc[copy['业务员名称'].str.contains('张|赵')]
copy3 = copy.loc[copy['业务员名称'].str.startswith('张')]
copy3 = copy.loc[copy['业务员名称'].str.endswith('三')]
copy4 = copy.loc[copy['学号'].str.isnumeric()] #是否为数值型的字符串
copy5 = copy.loc[copy['英文名'].str.islower()] #所有字符是否为小写,isupper为是否为大写 # 对列进行过滤:过滤值全一样的列
data = data.loc[:, data.nunique() != 1]

字符串类型字段抽取特征-str.extract

# se.str.extract能抽取一组或多组正则表达式匹配的字符串,根据括号()决定返回几组匹配字符串
# expend=True(默认),不管几组,都返回一个DataFrame;expand=False,若是一组返回Series,多组返回一个DataFrame
# 字符串前面加“r”是为了防止字符转义。如果字符串中出现“\t”,不加“r”的话“\t”就会被转义,而加了“r”之后“\t”就能保留原有的样子
extract_df = data['auth_capital'].str.extract(r'([\d\.,]+)(.*)', expand=True) se = pd.Series(['注册资本:5,946.67万元人民币', '注册资本:5946.67万港币'])
extract = se.str.extract('([0-9.,]+)(.*)') # 这里点号不用\貌似也不影响
print(extract)
'''
0 1
0 5,946.67 万元人民币
1 5946.67 万港币
''' '''
正则表达式:
. 匹配任何字符
* 前面出现的正则表达式匹配0次或多次
+ 前面出现的正则表达式匹配1次或多次
? 前面出现的正则表达式匹配0次或1次
\d [0-9]
\w [A-Za-z0-9]
\. 加转义符,表示真正意义的点号
[] 匹配括号中的任意一个字符
() 匹配封闭括号中正则表达式,并保存为子组,如:f(oo|u)bar
''' # \d+(\.\d*)?    表示简单浮点数,即任意个十进制数字,后面跟一个可选的小数点,然后跟0或多个十进制数

缺失数据处理

df['one'].isnull()
df['one'].notnull()
df['one'].sum() # 若有缺失数据(NaN),求和时视为0,这里不会报错 # 查看数据缺失情况
# 方法一
print(df.info())
# 方法二(推荐)
null_se = df.isnull().sum() # 生成一个Series
null_se = null_se[null_se > 0] # 过滤不为空的字段
print(null_se)
# 方法三:1表示不含缺失值,2表示含缺失值(notnull()结果只有True和False)
# 1表示不含缺失值,2表示含缺失值(notnull()结果只有True和False)
print(df.notnull().nunique()) df.fillna(0)
# 对某一列进行处理
df['A2'] = df['A2'].fillna(1)
df['A7'] = df['A7'].fillna(df['A7'].mean()) # pad/fill 填充方法向前
# bfill/backfill 填充方法向后
df.fillna(method='pad', inplace=True) df.dropna() # 默认axis=0,按行删除,若一行中有NaN,删除该行
df.dropna(axis=1) # 按列删除
df.dropna(inplace=True, thresh=10) #thresh表示一行(axis=1为列)中最少非缺失值数量,小于此值就删除
df.dropna(how="any") #how="any"(默认)表示只要含有缺失值就删除,how="all"表示全部是缺失值才删除
df = df.dropna(subset=['A']) # 删除某一列是空值的行
# 等同于
df = df[df['A'].notnull()] # 利用方法replace
df.replace({1000: 10, 2000: 20})
data['chol'].replace(564,246,inplace=True) # 把小于0的值当做缺失值,先把其变成NaN
for col_name, value in data.dtypes.iteritems():
if value != 'object':
data[col_name] = data[col_name].map(lambda x: np.nan if x < 0 else x)
  • 使用KNN填充缺失值
# KNNImputer需要sklearn0.22及以上版本才有
# 升级anaconda中的sklearn: pip install -U scikit-learn==0.22
from sklearn.impute import KNNImputer imputer = KNNImputer(n_neighbors=10)
data_imputer = imputer.fit_transform(data) # 输出为numpy类型,需要重新赋值
data = pd.DataFrame(data_imputer, columns=data.columns) # 由于KNN填充缺失值方式会把所有数据都转成float, 因此需要重新定义数据集数据类型
def define_type(data):
# float: rectal_temperature, nasogastric_reflux_PH, packed_cell_volume, total_protein, abdomcentesis_total_protein
float_col_list = ['rectal_temperature', 'nasogastric_reflux_PH', 'packed_cell_volume', 'total_protein', 'abdomcentesis_total_protein']
for col_name in data.columns:
if col_name in float_col_list:
data[col_name] = data[col_name].astype(float)
else:
data[col_name] = data[col_name].astype(int)
define_type(data)
  • 使用拉格朗日插值方式填充缺失值
from scipy.interpolate import lagrange
#s为列向量,n为被插值的位置,k为取前后的数据个数,默认为5
def ployinterp_column(s, n, k=5):
y = s[list(range(n-k, n)) + list(range(n+1, n+1+k))] #取数
y = y[y.notnull()] #剔除空值
return lagrange(y.index, list(y))(n) null_se = data.isnull().sum()
null_se = null_se[null_se > 0] # 获得含缺失值的列
for col_name in null_se.index:
for i in data.index:
if (data[col_name].isnull())[i]: #如果为空即插值
# 使用loc对data重新赋值
data.loc[i, col_name] = ployinterp_column(data[col_name], i)
  • 数据分析空处理规则:

    • NaN -- 默认值(政策、法规、规范)

    • NaN -- 序列型用中位数(median)、数值型用均值(mean)、类别型用众数(mode, 注意其结果为Series, 需要加[0]) (序列型:如疾病的严重程度,一般分为轻1、中2、重度3,数字大小有严重等级关系)(类别型:如血型,一般分为A、B、O、AB四个类型,用1-4表示,数字大小没有等级关系)

    data['小区房屋出租数量'] = data['小区房屋出租数量'].fillna(data['小区房屋出租数量'].mean())
    data['地铁站点'] = data['地铁站点'].fillna(data['地铁站点'].median())
    data['出租方式'] = data['出租方式'].fillna(data['出租方式'].mode()[0])
    • NaN -- 向前、向后(数据波动有规律)

    • NaN -- replace(明显错误)

    • NaN -- 逼近值(拉格朗日opp、牛顿插值oop)

    • NaN -- 删除(少于5%,不一定)行、列 (利用参数thresh(有效数据的最低要求), 5%需要手动计算一下)

异常数据处理

# 方式一:用箱线图方式去除异常点
def check_exception(se):
Q1 = se.quantile(0.25)
Q3 = se.quantile(0.75)
IQR = Q3 - Q1
up = Q3 + 1.5 * IQR
down = Q1 - 1.5 * IQR
me = se.median()
se_ex = se[(se > up) | (se < down)]
if len(se_ex) > 0:
se = se.map(lambda x: me if x > up or x < down else x)
print(se.describe())
return se for i in range(1, 73):
col_name = 'F%d' % i
data[col_name] = check_exception(data[col_name]) # 方式二:用2倍或3倍标准差方式处理
for i in range(15, 20):
col_name = 'A%d' % i
mean = data[col_name].mean()
std = data[col_name].std()
data[col_name] = data[col_name].map(lambda x: mean if x > mean + 2 * std or x < mean - 2 * std else x) # 方式三:根据箱线图判定异常值
df_A10_A13 = data.loc[:, 'A10':'A13']
df_A10_A13.plot.box() for i in range(10, 14):
col_name = 'A%d' % i
mean = np.mean(data[col_name])
data[col_name] = data[col_name].map(lambda x: mean if x > 50 else x)

数据相关性

Pearson相关系数

  • |r|<=0.3 不存在线性相关
  • 0.3 < |r| < 0.5 低度线性相关
  • 0.5 < |r| <=0.8 显著线性相关
  • |r| > 0.8 高度线性相关

数据深度克隆

df.copy(deep=true)

df.pipe/df.apply/se.map

  • df.pipe与se.map的区别
def adder(ele1,ele2):
return ele1+ele2 df=df.pipe(adder,20) # 方法1通过pipe调用操作函数,并设置叠加值
# df+=20 # 方法2直接将df叠加值即可,pandas最新管道用法
print('管道将DataFrame的所有元素叠加20:') #通过map函数仅对指定列运算
myArray=np.random.randn(5,3)
print(myArray)
df = pd.DataFrame(myArray,columns=['col1','col2','col3'])
df=df['col1'].map(lambda x:x*100)
  • df.apply(aggfunc) axis = 0(默认),按列处理;axis=1,按行处理,将一行作为一个Series传入aggfunc中
  • se.map(aggfunc) 它是Series的函数,aggfunc只能传入一个参数
# 灵活使用自定义函数
def get_hospital_name(hospital_no):
flag = str(hospital_no)[:2]
if flag == '51':
return '甲'
if flag == '52':
return '乙'
return '丙'
data['hospital_name'] = data['hospital_no'].map(get_hospital_name)

统计

df.pct_change()
df.cov(df2)
df.corr(df2)

分组聚合过滤


df.aggregate(np.sum) # 可以简写为df.agg # 分组
print(df.groupby('Team').groups) # 注意df.groupby('Team')结果显示的是对象内存
grouped = df.groupby('Year') # 其结果是一个元组(groupby_name, df_group),它可以用for进行遍历
#查看分组
print(grouped.get_group(2014)) # 获取某个组别数据 # 根据多个字段分组
grouped = df.groupby(['Year', 'Month']) # 聚合(aggregate) - 先分组,再聚合
# 使用numpy标准函数:若使用一个函数(且不带中括号),生成一个Series, 否则生成一个DataFrame,列名为函数名,如sum,mean
print(grouped['Points'].agg(np.mean))
# 等同于
print(grouped['Points'].mean()) # 使用的是Pandas函数
# 多个列
print(grouped[['Points', 'Height']]).agg(np.mean)
# 多种集合函数
print(grouped['Points'].agg([np.sum, np.mean, np.std]))
# 字典方式
print(grouped.agg({'Points': np.mean})) # 注意与上面的区别:上面生成一个Series, 字典方式和带中括号方式都是生成一个DataFrame
print(grouped['Points'].agg([np.mean])) # 带中括号就会生成DataFrame # 使用字典方式实现不同字段使用不同聚合函数(包含自定义函数)
# 注意这里的区别:groupby后直接agg,不用取某一个字段
df_gr = data.groupby('No').agg({'Close': cal_perc_fun, 'Volume': np.sum, 'High': np.amax, 'Low': [np.amin, np.amax] }) # 其中cal_perc_fun为自定义函数,也可以写成lambda函数
# 生成的df_gr字段,若没有一个字段多个函数,直接就是字段名;否者为复合字段名,为元组形式,如:
#MultiIndex([('Close','cal_perc_fun'),('Volume','sum'),('High','amax'),('Low','amin'),( 'Low','amax')])
# 取值方式:df_gr[('Low', 'amin')] # 注意上面的聚合函数若用numpy函数,就为np.***; 若为panda函数就需要加引号
df_gr = data.groupby('No').agg({'Volume': np.sum, 'High': 'max', 'Low': 'first'}) # 在多重分组时,若不想生成复合索引,使用参数as_index=False, 即可将分组字段作为列来呈现
data_gr = data.groupby(['id03', 'id04', 'id05'], as_index=False)['id00'].count()
# 等同于
data_gr = data.groupby(['id03', 'id04', 'id05'])['id00'].count().reset_index() # 取分组后每组中的第一个不为NaN值(first())
df_e = data.groupby('HEAT_NAME').first().loc[:, 'E1':'E15'] # 灵活使用自定义聚合函数
# 注意:若分组后,只对一个量进行聚合操作,传过来的就是一个Series
def lived_ratio(se):
se_lived = se[se == 1]
return len(se_lived) / len(se) * 100
data_gr = data.groupby('hospital_name')['outcome'].agg(lived_ratio) # 计算RFM值例子
def R_value(se):
se = se.sort_values(ascending=False) # 不会影响调用函数的数据源
se.index = range(len(se)) # 也可以不用重新定义index, 下面se[0]换成se.iloc[0]
latest_date = pd.to_datetime(se[0], format='%Y-%m-%d %H:%M:%S')
now_date = pd.to_datetime('2019-12-31 23:59:59', format='%Y-%m-%d %H:%M:%S')
delta = now_date - latest_date
return delta.total_seconds() / (24 * 3600) # 返回相隔小时数
data_gr = data.groupby('买家会员名').agg({'订单付款时间': [R_value, np.size], '买家实际支付金额': np.sum})
data_gr.columns = ['R-最近消费时间间隔', 'F-消费频率', 'M-消费金额'] # 使用自定义函数
print(grouped['Points'].transform(lambda x: (x-x.mean())/x.std * 10)) # 过滤
print(df.groupby('Team').filter(lambda x: len(x) > 3)) # 返回三次以上参加的队伍

透视表

'''
step4:数据透视表操作,每个地区的业务员分别赚取的利润总和与利润平均数
'''
pivot_table = pd.pivot_table(sheet1_shee2_merge, index='地区名称', columns='业务员名称', values='利润', aggfunc=[np.sum, np.mean])
print('每个地区的业务员分别赚取的利润总和与利润平均数透视表:')
print(pivot_table)
print('********************************************************************')
'''
sum ... mean
业务员名称 倪仲涛 刘仕祯 卞思宝 吴雯龙 尚庆龙 ... 陈国聚 陈恩泽 高鹏 麦豪 黄佳成
地区名称 ...
上海 NaN NaN NaN NaN NaN ... NaN 30.0 200.0 780.0 360.0
北京 NaN NaN 420.0 NaN NaN ... NaN NaN NaN NaN NaN
广州 300.0 170.0 NaN NaN 1200.0 ... NaN NaN NaN NaN NaN
深圳 NaN NaN NaN 330.0 NaN ... 3200.0 NaN NaN NaN NaN [4 rows x 40 columns]
''' # 或者将values属性放在aggfunc中
pivot_table = pd.pivot_table(df, index='month', columns='type', aggfunc={'flag': [np.sum, len]}) # 统计个数用len
# 多个值
pivot_table = pd.pivot_table(df, index='month', columns='type', aggfunc={'flag': [len, np.sum], 'flag2': sum}) #求和既可以用np.sum也可以用sum # 使用fill_value参数填充NaN
# 当希望将id05列与id15列不同的值的组合方式都呈现出来,可以这两列分别放入参数index和columns中
data8 = data2.pivot_table(values='target', index='id05', columns='id15', aggfunc='std', fill_value=0)
'''
id15 45c48c c4ca42 cfcd20
id05
07078a 30.833425 0.000000 29.330063
15dfea 5.432277 0.000000 4.345821
336669 33.132657 10.297472 31.500252
e4c2e8 25.179980 0.000000 25.510223
''' # 注意与将id05与id15放在一起的区别
data8 = data2.pivot_table(values='target', index=['id05', 'id15'], aggfunc='std', fill_value=0)
'''
target
id05 id15
07078a 45c48c 30.833425
cfcd20 29.330063
15dfea 45c48c 5.432277
cfcd20 4.345821
336669 45c48c 33.132657
c4ca42 10.297472
cfcd20 31.500252
e4c2e8 45c48c 25.179980
cfcd20 25.510223
'''

crosstab

# 分布统计不同赛季输和赢的场数
knicks2 = pd.crosstab(knicks.season, knicks.win)
'''
win L W
season
07-08 59 23
08-09 50 32
09-10 53 29
10-11 40 42
11-12 30 36
'''

哑变量

# 当值只有两类时
df['win_flag'] = df['win'].map({'L': 0, 'W': 1}) # 当值有多类时
def dummies(data, col_name_list):
for col_name in col_name_list:
# 类别大于2类的列做哑变量处理
if len(data[col_name].value_counts()) > 2:
tempDf = pd.get_dummies(data[col_name], prefix=col_name)
data = pd.concat([data, tempDf], axis=1)
data.drop(col_name, axis=1, inplace=True)
return data

按区间切割赋值

  • pd.cut
bins = [0, 1932, 2345, 10000]
groups = ['低', '中', '高']
Dataframesale['分组'] = pd.cut(df['利润'], bins, labels=groups)
print(df)
print('********************************************************************')
'''
地区名称 利润 分组
0 上海 1970.0 中
1 北京 1820.0 低
2 广州 2720.0 高
3 深圳 8330.0 高
'''
  • pd.qcut
# 将Age字段按照等宽间距划分为5等分,并统计输出每个区间的人数。
se1 = pd.qcut(full['Age'], q=5, labels=['L1', 'L2', 'L3', 'L4', 'L5'])
print('将Age字段按照等宽间距划分为5等分,并统计输出每个区间的人数:', se1.value_counts())

连接

rs = pd.merge(left, right, on='id')
rs = pd.merge(left, right, on=['id', 'subject_id']) # 若连接的表之间有相同字段,可以通过参数suffixes加后缀,默认为['_x', '_y']
df_mer = pd.merge(df_2015, df_2016, on=['Month', 'Day', 'Hour'], suffixes=['_2015', '_2016']) rs = pd.merge(left,right,on='subject_id',how='left')
# left/right/outer(全连接)/inner 默认为inner a= pd.DataFrame({'key': ['K0', 'K1', 'K2', 'K3', 'K4', 'K5'], 'A': ['A0', 'A1', 'A2', 'A3', 'A4', 'A5']})
b = pd.DataFrame({'key': ['K0', 'K1', 'K9'],'B': ['B0', 'B1', 'B2']})
c=a.merge(b,how='outer') # 不写on参数,默认是按照相同列名作为连接键
print(c)
'''
key A B
0 K0 A0 B0
1 K1 A1 B1
2 K2 A2 NaN
3 K3 A3 NaN
4 K4 A4 NaN
5 K5 A5 NaN
6 K9 NaN B2
'''

合并

ignore_index设置为True生成连续索引

rs = pd.concat([one,two], keys=['x','y'], ignore_index=True)
#使用keys把特定的键与每个碎片的DataFrame关联起来
#ignore_index设置为True生成连续索引,一般在axis=0时使用 rs = pd.concat([one,two], axis=1) #横向合并 注意多个df一定要用[] rs = one.append(two)
rs = one.append([two, one, two])

文件IO

df = pd.read_csv('temp.csv', index_col=['S.No']) # 使用某列作为索引
df = pd.read_csv('temp.csv', dtype={'Salary': np.float64}) # 更改某列的数据类型
# 使用header指定标题行,使用names自定义列名; 若文件不含标题行,使用header=None
df = pd.read_csv('temp.csv', names=['a', 'b', 'c'], header=0)
# skiprows跳到指定行数开始显示
df = pd.read_csv("temp.csv", skiprows=2)
# 若第1行是标题,想跳过第2、3行,skiprows用range赋值
df = pd.read_csv("temp.csv", header=0, skiprows=range(1, 3)) # 读取多个文件
def read_data():
file_names = os.listdir('./data/')
file_names = [item for item in file_names if item.endswith('.csv')]
df = pd.DataFrame()
for i in range(len(file_names)):
df_temp = pd.read_csv('./data/' + file_names[i])
df_temp['No'] = file_names[i].split('.')[0]
df = pd.concat([df, df_temp], ignore_index=True)
return df

时间序列

datelist = pd.date_range('2020/5/21', periods=5, freq='M')
print(datelist) # 注意它是一个序列,不是Series
'''
DatetimeIndex(['2020-05-31','2020-06-30','2020-07-31','2020-08-31','2020-09-30'],dtype='datetime64[ns]',freq='M')
'''
# 注意DatetimeIndex类型的基本属性:year/month/day/hour/minute/second, 注意这里与下面datatime64类型字段读取年、月、日等属性用法的区别
print(datelist.year) # 结果是Int64Index
print(datelist.month) # 日期时间类型字段
# 应用案例
def R_value(se):
se = se.sort_values(ascending=False)
se.index = range(len(se))
# 一般若文件保存的是日期时间格式,使用read_csv会自动解析为datatime64类型(通过dtype查看)
# 否则使用下面语句转换
latest_date = pd.to_datetime(se[0], format='%Y-%m-%d %H:%M:%S')
# 对单个时间转换后为Timestamp类型
now_date = pd.to_datetime('2019-12-31 23:59:59', format='%Y-%m-%d %H:%M:%S')
delta = now_date - latest_date
return delta.total_seconds() / (24 * 3600) # 提取日期时间类型字段中的年、月、日
df['Year'] = df['Joined date'].dt.year
df['Month'] = df['Joined date'].dt.month
df['Day'] = df['Joined date'].dt.day
df['Week'] = df['Joined date'].dt.week
df['Hour'] = df['Joined date'].dt.hour
df['Minute'] = df['Joined date'].dt.minute
df['Second'] = df['Joined date'].dt.second # 两列datetime类型相减求相距天数dt.days和秒数dt.total_seconds(),注意:前者没括号,后者有!!!
df = pd.DataFrame({'name': list('ABCDE'), 'date': pd.date_range('2020/5/21', periods=5, freq='D'), 'date2': pd.date_range('2020/9/21', periods=5, freq='M')})
delta_days = (df['date2'] - df['date']).dt.days
delta_seconds = (df['date2'] - df['date']).dt.total_seconds()

DataFrame赋值时省略index=和columns=**

df = pd.DataFrame([['2018', 88], ['2019', 99]], ['year', 'data'], ['000', '001'])

# 参数中第一个是value, 第二个是index, 第三个是columns

Python数据分析易错知识点归纳(三):Pandas的更多相关文章

  1. python函数-易错知识点

    定义函数: def greet_users(names): #names是形参 """Print a simple greeting to each user in th ...

  2. Java易错知识点(1) - 关于ArrayList移除元素后剩下的元素会立即重排

    帮一个网友解答问题时,发现这样一个易错知识点,现总结如下: 1.易错点: ArrayList移除元素后,剩下的元素会立即重排,他的 size() 也会立即减小,在循环过程中容易出错.(拓展:延伸到所有 ...

  3. Python数据分析与挖掘所需的Pandas常用知识

    Python数据分析与挖掘所需的Pandas常用知识 前言Pandas基于两种数据类型:series与dataframe.一个series是一个一维的数据类型,其中每一个元素都有一个标签.series ...

  4. JavaScript易错知识点整理

    前言 本文是我学习JavaScript过程中收集与整理的一些易错知识点,将分别从变量作用域,类型比较,this指向,函数参数,闭包问题及对象拷贝与赋值这6个方面进行由浅入深的介绍和讲解,其中也涉及了一 ...

  5. JavaScript 易错知识点整理

    本文是我学习JavaScript过程中收集与整理的一些易错知识点,将分别从变量作用域,类型比较,this指向,函数参数,闭包问题及对象拷贝与赋值这6个方面进行由浅入深的介绍和讲解,其中也涉及了一些ES ...

  6. JavaScript易错知识点整理[转]

    前言 本文是我学习JavaScript过程中收集与整理的一些易错知识点,将分别从变量作用域,类型比较,this指向,函数参数,闭包问题及对象拷贝与赋值这6个方面进行由浅入深的介绍和讲解,其中也涉及了一 ...

  7. JS易错知识点

    JAVASCRIPT易错知识点整理 前言 本文是学习JavaScript过程中收集与整理的一些易错知识点,将分别从变量作用域,类型比较,this指向,函数参数,闭包问题及对象拷贝与赋值这6个方面进行由 ...

  8. JavaScript易错知识点

    JavaScript易错知识点整理1.变量作用域上方的函数作用域中声明并赋值了a,且在console之上,所以遵循就近原则输出a等于2. 上方的函数作用域中虽然声明并赋值了a,但位于console之下 ...

  9. Python数据分析:手把手教你用Pandas生成可视化图表

    大家都知道,Matplotlib 是众多 Python 可视化包的鼻祖,也是Python最常用的标准可视化库,其功能非常强大,同时也非常复杂,想要搞明白并非易事.但自从Python进入3.0时代以后, ...

  10. Python入门---易错已错易混淆----知识点

    1.not 1 or 0 and 1 or 3 and 4 or 5 and 6 or 7 and 8 and 9 结果会输出啥? 根据优先级:(not 1) or (0 and 1) or (3 a ...

随机推荐

  1. 学会提示-AI时代职场必修课

    作者:京东 何雨航 " 上个时代要学会提问,这个时代要学会提示." 引言 当你在写提数代码时,小张已经完成了数据分析:当你正在整理材料时,小王却在和对象逛环球影城:述职时,你发现小 ...

  2. 非关系型数据库---Redis安装与基本使用

    一.数据库类型 关系数据库管理系统(RDBMS) 非关系数据库管理系统(NoSQL) 按照预先设置的组织机构,将数据存储在物理介质上(即:硬盘上) 数据之间可以做无关联操作 (例如: 多表查询,嵌套查 ...

  3. Appweb配置

    Appweb配置       具体配置网页=> https://www.embedthis.com/appweb/doc/users/configuration.html         具体参 ...

  4. Docker快速部署Hadoop环境

    文章目录 安装环境 安装过程 拉取镜像 在Docker中创建网络,方便通信 创建Master节点 创建slave1和slave2节点 分别进入三个容器修改hosts文件 在Master执行集群初始化 ...

  5. Redis篇一之基础数据结构

    文章目录 Redis的数据结构 String类型**** Hash类型 List类型 Set类型 SortedSet类型 BitMap类型 HyperLogLog 总结 Redis诞生于2009年全称 ...

  6. 【Vue3】引入组件Failed to resolve component: MyButton If this is a native custom element

    引入组件时页面上并没有出现组件的影子,其他元素正常,初步确定是组件引入部分语法出了问题,打开开发者工具看到控制台报出错误代码: Failed to resolve component: MyButto ...

  7. 2021-03-20:给定一个二维数组matrix,其中的值不是0就是1,返回全部由1组成的子矩形数量。

    2021-03-20:给定一个二维数组matrix,其中的值不是0就是1,返回全部由1组成的子矩形数量. 福大大 答案2021-03-20: 按行遍历二维数组,构造直方图. 单调栈,大压小.有代码. ...

  8. 2021-02-23:给定一个正数n,求n的裂开方法数。规定:后面的数不能比前面的数小 。比如4的裂开方法有: 1+1+1+1、1+1+2、1+3、2+2、4,5种,所以返回5。

    2021-02-23:给定一个正数n,求n的裂开方法数.规定:后面的数不能比前面的数小 .比如4的裂开方法有: 1+1+1+1.1+1+2.1+3.2+2.4,5种,所以返回5. 福哥答案2021-0 ...

  9. 软硬件--智能穿戴常见BUG及原因分析

    软硬件--智能穿戴常见BUG及原因分析 1.手表有常亮功能(类似熄屏表盘),开启常亮暗屏状态下 按侧键,设备时间出现倒退现象:频率切换相关问题: 2.手表有常亮功能(类似熄屏表盘),开启常亮暗屏状态下 ...

  10. 代码随想录算法训练营Day9|字符串KMP算法总结

    代码随想录算法训练营 代码随想录算法训练营Day9字符串|KMP算法 8. 实现 strStr() 459.重复的子字符串 字符串总结 双指针回顾 28. 实现 strStr() KMP算法 题目链接 ...