Datawhale-Pandas-Task02-Pandas基础

本文详细介绍了Pandas库的基础知识,包括文件读写、Series和DataFrame数据结构、常用统计函数、替换功能、排序和窗口函数。对比了Pandas与R语言在数据处理上的异同,强调了Pandas在数据处理的便利性和全面性。并提供了口袋妖怪数据集的实战练习,帮助读者巩固所学。
摘要由CSDN通过智能技术生成

文件的读写

pandas集成了很多文件格式的读写,R中除了文本格式,其他格式都分散在各种包中,pandas使用体验更好一点。

另外,R的read.csv读取数据是,默认stringsAsFactors = TRUE,这个我认为是体验不太好的地方,好在4.0版本开始修改默认为FALSE

强烈推荐R中的一个神级包data.table,对大数据的读写有超高的效率,Python中也实现了类似的包,datatable

格式Python读Python写R读R写
CSVpd.read_csvpd.to_csvread.csv
data.table::fread
write.csv
data.table::fwrite
TXTpd.read_tablepd.to_csvread.tablewrite.table
固定宽度Textpd.read_fwfNAread.fwfNA
Excelpd.read_excelpd.to_excelreadxl::read_excelwritexl::write_xlsx
JSONpd.read_jsonpd.to_jsonjsonlite::fromJSONjsonlite::toJSON

基本数据结构

Series

索引在pandas中是非常重要的概念,但在R中这个概念就很弱,甚至在R的DataFrame中尽量避免使用行名(R的行名相当于pandas中dataframe的索引)。

s = pd.Series(data = [100, 'a', {'dic1':5}],
  index = pd.Index(['id1', 20, 'third'], name='my_idx'),
  dtype = 'object',
  name = 'my_name')

s.shape

s['third'] ## 返回dict
s[['third']] ## 返回series
# s = pd.Series(np.arange(5), dtype=np.float32)

s <- list(
  id1 = 100,
  `20` = 'a',
  third = list(
    dic1 = 5
  )
)

length(s)

s[['third']] 
s['third']

DataFrame

对DataFrame数据的操作,pandas的[][[]]操作与R正好相反。

R中$也可以获取字段数据,但只能获取一列,而且是模糊匹配,[[]]也可以通过exact = FALSE实现模糊匹配字段。R的这个特性,我只在明确知道字段名称,而自己当时又特别懒的情况下,临时使用。也许是我没发现这个功能在其他地方有什么神奇效果,但我觉得这个弊大于利。

# Python
df = pd.DataFrame(
  data = {
    'col_0': [1,2,3], 
    'col_1':list('abc'), 
    'col_2': [1.2, 2.2, 3.2], 
    'mycol': range(3)},
  index = ['row_%d'%i for i in range(3)])

df['col_0'] # 返回series
df[['col_0']] # 返回dataframe

df.col_0.values # 返回numpy.ndarray
df.col_0.to_numpy() # 返回numpy.ndarray
# R
df <- data.frame(
  col_0 = 1:3,
  col_1 = c('a', 'b', 'c'),
  col_2 = c(1.2, 2.2, 3.2),
  mycol = 0:2,
  stringsAsFactors = FALSE
)

df["col_0"] # 返回dataframe
df[["col_0"]] # 返回vector

df$col_0 # 返回vector
df[, "col_0"] # 返回vector

df$my
df[['my', exact = FALSE]]

# R-dplyr
pull(df, col_0)
pull(df, col_0, col_1) ## 可以直接用col_1给col_0命名

常用函数

# Python
df = pd.read_csv('data/learn_pandas.csv')
# R
df <- read.csv('data/learn_pandas.csv', stringsAsFactors = FALSE)
内容PythonR
行名df.indexrownames(df)
列名df.columnscolnames(df)
字段类型df.dtypessapply(df, class)
字段信息df.infostr(df)
主要统计量df.describe()summary(df)
字段数据df[‘School’]df[[‘School’]]
df$School
维度df.ndim-
维度df.sizeprod(dim(df))
维度df.shapedim(df)
行数df.shape[0]nrow(df)
列数df.shape[1]ncol(df)
列数df.head()head(df)
列数df.tail()tail(df)

特征统计函数

pandas可以直接使用统计函数,对各列进行统计,使用起来非常方便。

R与pandas有所差异,只有几个可以直接实现,但R中有summary可以直接查看所有列几个常用的统计指标,其他也可以使用apply系列函数实现。

# Python
df_demo = df[['Height', 'Weight']]

df_demo.sum()
df_demo.mean()
df_demo.max()
# R
df_demo <- df[, c('Height', 'Weight')]
summary(df_demo)

colSums(df_demo, na.rm = TRUE)
colMeans(df_demo, na.rm = TRUE)
sapply(df_demo, max, na.rm = TRUE)

替换函数

pandas的replace功能比R的replace功能更加全面。

# Python
df['Gender'].replace({'Female':0, 'Male':1}).head()
# R
s <- c(-1, 1.2345, 100, -50)

round(s, 2)
abs(s)
ifelse(s > 2, 2, ifelse(s < 0, 0, s))
replace(replace(s, s < 0, 0), s > 2, 2)

R中的clip是graphics包,用于绘图的。想到两种方式,ifelse和replace,以为ifelse会快,结果发现replace性能更好。

# Python
s = pd.Series([-1, 1.2345, 100, -50])

s.round(2)
s.abs()
s.clip(0, 2)
# R
s <- c(-1, 1.2345, 100, -50)

round(s, 2)
abs(s)
ifelse(s > 2, 2, ifelse(s < 0, 0, s))
replace(replace(s, s < 0, 0), s > 2, 2)
exprminmeanmedianmax
ifelse4.9591838.7309167.018489113.33355
replace2.1359272.6132912.19771012.00995

唯一值

pandas使用uniquenunique分别获获取序列的唯一值和唯一值的个数。

R中也有unique,功能相同。R中没有直接实现nunique的函数,需要使用length计算。

# Python
df['School'].unique()
df['School'].nunique()
# R
unique(df$School)
length(unique(df$School)) 

# R-dplyr 
n_distinct(df$School)

pandas使用value_counts获取每个唯一值的数量

R中有table,dplyr的count

# Python
df['School'].value_counts()
# R
table(df$School)

# R-dplyr 
count(df, School)

pandas和R都有duplicated来查找重复项,功能基本相同,pandas比R多一个模式keep = False

df.duplicated的关键参数是keep:

  • first 表示除了第一条,把其余相同值都标示为重复【默认值】
  • last 表示除了最后一条,把其余相同值都标示为重复
  • False 表示把所有存在相同指的都标示为重复

R中duplicated的关键参数是fromLast,只能直接实现firstlast的功能,False的功能需要结合两者使用。

# Python
df_demo = df[['Gender','Transfer','Name']]

df_demo.duplicated()
df_demo.duplicated(keep = 'last')
df_demo.duplicated(keep = False)
# R
df_demo <- df[, c('Gender','Transfer','Name')]

duplicated(df_demo)
duplicated(df_demo, fromLast = TRUE) ## rev(duplicated(rev(df_demo)))
duplicated(df_demo) | duplicated(df_demo, fromLast = TRUE)

删除重复项dp.drop_duplicates的方式也是有三种,同df.duplicated

# Python
df_demo.drop_duplicates()

df_demo.drop_duplicates(['Gender', 'Transfer'])
df_demo.drop_duplicates(['Gender', 'Transfer'], keep = 'last')
df_demo.drop_duplicates(['Name', 'Gender'], keep = False)
# R
df_demo[!duplicated(df_demo), ]

df_demo[!duplicated(df_demo[, c('Gender', 'Transfer')]), ]
df_demo[!duplicated(df_demo[, c('Gender', 'Transfer')], fromLast = TRUE), ]
df_demo[!(duplicated(df_demo[, c('Name', 'Gender')]) | duplicated(df_demo[, c('Name', 'Gender')], fromLast = TRUE)), ]

# R-dplyr
distinct(df_demo)
df_demo %>% distinct(Gender, Transfer, .keep_all = TRUE)
# df_demo %>% group_by(Gender, Transfer) %>% filter(row_number() == 1)
df_demo %>% 
  group_by(Gender, Transfer) %>% 
  filter(row_number(desc(row_number())) == 1)

df_demo %>% 
  group_by(Name, Gender) %>% 
  filter(n() == 1)

排序函数

# Python
df_demo = df[['Grade', 'Name', 'Height', 'Weight']].set_index(['Grade','Name'])
   
df_demo.sort_values(by = 'Height')
df_demo.sort_values('Height', ascending=False)
df_demo.sort_values(['Weight','Height'],ascending=[True,False])
# R
df_demo <- df[, c('Grade', 'Name', 'Height', 'Weight')]

df_demo[order(df_demo$Height), ]
df_demo[order(df_demo$Height, decreasing = TRUE), ]
df_demo[order(df_demo$Weight, -df_demo$Height), ]

# R-dplyr
arrange(df_demo, Height)
arrange(df_demo, desc(Height))
arrange(df_demo, Weight, desc(Height))

apply函数

pandas的apply函数与R的apply系列函数功能基本相同。

pandas的mad与R的mad函数两种的运算逻辑是不一样的。pandas的逻辑是Mean Absolute Deviation,但称为Average Absolute Deviation更合适,R的逻辑是Median Absolute Deviation。后续pandas也会对这个进行优化,详见ENH: calculate average absolute difference by mean, median or mode #11787

# Python
df_demo = df[['Height', 'Weight']]

df_demo.apply(lambda x:x.mean())
df_demo.apply(lambda x:x.mean(), axis=1)

## constant * Median(abs(x - center))
df_demo.apply(lambda x:(x-x.mean()).abs().mean())
df_demo.mad()
# R
df_demo <- df[, c('Height', 'Weight')]

apply(df_demo, 2, mean, na.rm = TRUE)
apply(df_demo, 1, mean, na.rm = TRUE)

apply(df_demo, 2, function(x) mean(abs(x-mean(x, na.rm = TRUE)), na.rm = TRUE))

## R的mad函数逻辑是constant * Median(abs(x - center))
apply(df_demo, 2, mad, na.rm = TRUE)
apply(df_demo, 2, function(x) 1.4826 * median(abs(x[!is.na(x)]-median(x[!is.na(x)]))))

窗口函数

滑动窗口

R base和dplyr都不支持滑动窗口函数,可以使用RcppRoll的roll系列函数、data.table的roll系列函数、roll的roll系列函数。

pandas的确是各种数据分析工具的集成,R中虽然有很多包可以实现,但pandas体验稍微好点。

# Python
s = pd.Series([1,2,3,4,5])
roller = s.rolling(window = 3)
roller.mean()
roller.sum()

s2 = pd.Series([1,2,6,16,30])
s2.rolling(3).cov()
s2.rolling(3).corr()
s2.rolling(3).apply(lambda x:x.mean())
# R
s <- 1:5

RcppRoll::roll_mean(s, 3, fill=NA, align="center") ## 默认为align
RcppRoll::roll_mean(s, 3, fill=NA, align="right")
RcppRoll::roll_mean(s, 3, fill=NA, align="left")

roll::roll_mean(s, width = 3) ## data.table::frollmean(s, 3)
roll::roll_sum(s, width = 3) ## data.table::frollsum(s, 3)

s2 <- c(1,2,6,16,30)
roll::roll_cov(s2, width = 3)
roll::roll_cor(s2, width = 3)
data.table::frollapply(s2, 3, mean)

扩展窗口

扩展窗口也就是累加窗口。

使用pandas的滑动窗口rolling和扩展窗口expanding,支持的运算函数是统一的,统一支持运算有agg、aggregate、apply、corr、count、cov、exclusions、is_datetimelike、is_freq_type、kurt、max、mean、median、min、ndim、quantile、skew、std、sum、validate、var。

# Python
s = pd.Series([1, 3, 6, 10])
s.expanding().sum() ## s.cumsum()
s.expanding().agg({"A": "sum", "B": "mean"})
# R
s <- c(1, 3, 6, 10])
cumsum(s)

指数加权窗口

练习

Ex1:口袋妖怪数据集

1 对 HP, Attack, Defense, Sp. Atk, Sp. Def, Speed 进行加总,验证是否为 Total 值

# Python
df = pd.read_csv('data/pokemon.csv')

all((df['Total'] - df[['HP', 'Attack', 'Defense', 'Sp. Atk', 'Sp. Def', 'Speed']].sum(axis=1)) == 0)
# R
df <- read.csv('data/pokemon.csv', stringsAsFactors = FALSE, check.names = FALSE) ## read.csv默认会将不合规行名进行替换

all(rowSums(df[, c('HP', 'Attack', 'Defense', 'Sp. Atk', 'Sp. Def', 'Speed')]) - df$Total == 0)

2 对于 # 重复的妖怪只保留第一条记录,解决以下问题:
a 求第一属性的种类数量和前三多数量对应的种类

# Python
df['Type 1'].nunique()
df['Type 1'].value_counts().head(3)
# R
length(unique(df[['Type 1']]))
head(sort(table(df[['Type 1']]), decreasing = TRUE), 3)

b 求第一属性和第二属性的组合种类

# Python
df_attr_have = df[['Type 1', 'Type 2']].drop_duplicates(keep = 'first')
df_attr_have.shape[0]
# R
df_attr_have <- dplyr::distinct(df[, c('Type 1', 'Type 2')])
nrow(df_attr_have)

c 求尚未出现过的属性组合

# Python
attr_1 = df['Type 1'].unique()
attr_2 = df['Type 2'].unique()
len(attr_1) * len(attr_2) - df_attr_have.shape[0]

attr_all = [(x, y) for x in attr_1 for y in attr_2]
attr_none_logical = [z not in [(df_attr_have['Type 1'].values[x], df_attr_have['Type 2'].values[x]) for x in range(df_attr_have.shape[0])] for z in attr_all]

np.array(attr_all)[np.array(attr_none_logical)]
# R
attr_1 <- unique(df[['Type 1']])
attr_2 <- unique(df[['Type 2']])
length(attr_1) * length(attr_2) - nrow(df_attr_haves)

attr_all <- paste(rep(attr_1, 19), rep(attr_2, 18))
attr_all[!(attr_all %in% paste(df_attr_have[['Type 1']], df_attr_have[['Type 2']]))]

df_attr_all <- expand.grid(unique(df[['Type 1']]), unique(df[['Type 2']]), KEEP.OUT.ATTRS = FALSE, stringsAsFactors = FALSE)
names(df_attr_all) <- c('Type 1', 'Type 2')
nrow(df_attr_all) - nrow(df_attr_have)

df_attr_all2 <- df_attr_all %>% 
  left_join(mutate(df_attr_have, is_have = 1)) %>% 
  filter(is.na(is_have))

3 按照下述要求,构造 Series :
a 取出物攻,超过120的替换为 high ,不足50的替换为 low ,否则设为 mid

# Python
df['Attack'].mask(df['Attack']>120, 'high').mask(df['Attack']<50, 'low').mask((50<=df['Attack'])&(df['Attack']<=120), 'mid')
# R
ifelse(
  df$Attack > 120, 'high',
  ifelse(df$Attack < 50, 'low','mid')
)

# R-dplyr
case_when(
  df$Attack > 120 ~ 'high',
  df$Attack < 50 ~ 'low',
  TRUE ~ 'mid'
)

b 取出第一属性,分别用 replace 和 apply 替换所有字母为大写

# Python
df['Type 1'].replace({i:str.upper(i) for i in df['Type 1'].unique()})
df['Type 1'].apply(lambda x:str.upper(x))
# R
toupper(df[['Type 1']])

c 求每个妖怪六项能力的离差,即所有能力中偏离中位数最大的值,添加到 df 并从大到小排序

# Python
df['Deviation'] = df[['HP', 'Attack', 'Defense', 'Sp. Atk', 'Sp. Def', 'Speed']].apply(lambda x:np.max((x-x.median()).abs()), 1)

df.sort_values('Deviation', ascending=False).head()
# R
df$Deviation <- apply(df[, c('HP', 'Attack', 'Defense', 'Sp. Atk', 'Sp. Def', 'Speed')], 1, function(x) max(x) - median(x))

df[order(df$Deviation, decreasing = TRUE), ]

Ex2:指数加权窗口

# Python
np.random.seed(0)
s = pd.Series(np.random.randint(-1,2,30).cumsum())
s.head()

s.ewm(alpha=0.2).mean().head()
# R
s <- py$s
se <- qcc::ewma(s, lambda = 0.2)
cummean(se$data)
# Python
def ewm_func(x, alpha=0.2):
	win = (1-alpha)**np.arange(x.shape[0])[::-1]
	res = (win*x).sum()/win.sum()
	return res

s.expanding().apply(ewm_func).head()
# Python
s.rolling(4).apply(ewm_func).head()

参考资料

总结

根据到现在的学习,在数据分析领域,pandas和R都有自己的特色,pandas在数据分析中的优点是工具集成、方法全面、使用方式统一,python基本靠pandas做到了R很多包的功能。R在数据分析中优点是工具全面、方法多样(有时候也是缺点)、统计知识(如mad函数)。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值