2019-03-25 Python Pandas 基本操作

时间:2022-05-08 00:18:42

新建表

data1 = {
"name": ["Tom", "Bob", "Mary", "James"],
"age": [18, 30, 35, 18],
"city": ["Bei Jing ", "Shang Hai ", "Guang Zhou", "Shen Zhen"]
} df1 = pd.DataFrame(data=data1)
df1

重命名列

df1.rename(columns={"name": "name1"}, inplace=True)
df1

重命名列的值

df1["sex"] = "male"
df1

重命名索引

user_age.index = ["Tom", "Bob", "Mary", "James"]
user_age

为索引取个值

user_age.index.name = "name"
user_age

访问行,获取第4个和第二个元素

# series
user_age[[3, 1]]
# dataframe
user_info.iloc[1:3]
# 每两行选一次数据
user_info[::2] # 筛选出名称为 Tom 的年龄
# 筛选出索引名称在 Tom 到 Mary 之间的数据
user_info.loc["Tom", "age"]
user_info.loc["Tom": "Mary"]
# 筛选出年龄这一列数据
user_info.loc[:, ["age"]]
# 筛选出性别属于 male 和 female的数据
user_info[user_info.sex.isin(["male", "female"])]
# 年龄大于20的
user_info.loc[user_info.age > 20, ["age"]]
user_info.loc[lambda df: df.age > 20, lambda df: ["age"]]

访问列

user_info[["city", "age"]]
# 对所有信息进行反转
user_info[::-1]

  

排序:如果想要按照列进行倒序排,可以设置参数 axis=1ascending=False

user_info.sort_index(axis=1, ascending=False)
# 按实际值来排序
user_info.sort_values(by="age")

  

函数

# 对 Series 来说,apply 方法 与 map 方法区别不大。
user_info.age.apply(lambda x: "yes" if x >= 30 else "no")
# 对 DataFrame 来说,apply 方法的作用对象是一行或一列数据(一个Series)
user_info.apply(lambda x: x.max(), axis=0)

类型操作

pd.to_numeric(user_info.height, errors="coerce")

 

缺失值处理

# 一行数据只要有一个字段存在空值即删除
user_info.dropna(axis=0, how="any") # 一行数据所有字段都为空值才删除
user_info.dropna(axis=0, how="all") # 一行数据中只要 city 或 sex 存在空值即删除
user_info.dropna(axis=0, how="any", subset=["city", "sex"]) #使用线性差值来填充
user_info.age.interpolate() #替换
user_info.replace({"age": 40, "birth": pd.Timestamp("1978-08-08")}, np.nan) #除了可以替换特定的值之外,还可以使用正则表达式来替换,如:将空白字符串替换成空值
user_info.city.replace(r'\s+', np.nan, regex=True) # 将无缺失值的值传给有缺失值的
age_new = user_info.age.copy()
age_new.fillna(20, inplace=True)
age_new
user_info.age.combine_first(age_new)

 

#我们可以使用 .cat.categories 来获取分类数据所有可能的取值 

user_info.cat.categories

  

分类数据也是支持使用 value_counts 方法来查看数据分布的

user_info.value_counts()

 

分类数据也是支持使用 .str 属性来访问的。例如想要查看下是否包含字母 "A",可以使用 .srt.contains 方法

user_info.str.contains("A")

 

#有时候,我们可能想要生成某个范围内的时间戳。例如,我想要生成 "2018-6-26" 这一天#之后的8天时间戳,如何完成呢?我们可以使用 date_range 和 bdate_range 来完成时间##戳范围的生成。

#date_range 默认使用的频率是 日历日,而 bdate_range 默认使用的频率是 营业日。当然#了,我们可以自己指定频率,比如,我们可以按周来生成时间戳范围

pd.date_range("2018-6-26", periods=8)
pd.bdate_range("2018-6-26", periods=8) # 按周来生成
pd.date_range("2018-6-26", periods=8, freq="W") #转换时间戳
pd.to_datetime(["2005/11/23", "2010.12.31"]) #时间偏移
from pandas.tseries.offsets import *
d = pd.Timestamp("2018-06-25")
d + DateOffset(weeks=2, days=5)
ts.shift(2, freq=Day()) #resample 表示根据日期维度进行数据聚合,可以按照分钟、小时、工作日、周、月、年等来作为日期维度
# 求出每个月的数值平均值
ts.resample("1M").mean()

  

 

通过 pd.merge 可以关联两个DataFrame,这里我们设置参数 on="name",表示依据 name 来作为关联键。

pd.merge(df1, df2, on="name")

关联后发现数据变少了,只有 3 行数据,这是因为默认关联的方式是 inner,如果不想丢失任何数据,可以设置参数 how="outer"

pd.merge(df1, df2, on="name", how="outer")

可以看到,设置参数 how="outer" 后,确实不会丢失任何数据,他会在不存在的地方填为缺失值。

如果我们想保留左边所有的数据,可以设置参数 how="left";反之,如果想保留右边的所有数据,可以设置参数 how="right"

pd.merge(df1, df2, on="name", how="left")

  

有时候,两个DataFrame中都包含相同名称的字段,如何处理呢?

我们可以设置参数 suffixes,默认 suffixes=('_x', '_y') 表示将相同名称的左边的DataFrame的字段名加上后缀 _x,右边加上后缀 _y

pd.merge(df1, df2, left_on="name1", right_on="name2", suffixes=("_left", "_right"))

除了 merge 这种方式外,还可以通过 join 这种方式实现关联。相比 mergejoin 这种方式有以下几个不同:

  • 默认参数on=None,表示关联时使用左边和右边的索引作为键,设置参数on可以指定的是关联时左边的所用到的键名
  • 左边和右边字段名称重复时,通过设置参数 lsuffixrsuffix 来解决。
df1.join(df2.set_index("name2"), on="name1", lsuffix="_left")

IO操作

#读取出来生成了一个 DataFrame,索引是自动创建的一个数字,我们可以设置参数 index_col 来将某列设置为索引,可以传入索引号或者名称
pd.read_csv("../data/user_info.csv", index_col="name") #Pandas 默认将第一行作为标题,但是有时候,csv文件并没有标题,我们可以设置参数 names 来添加标题。
data="Tom,18.0,2000-02-10,\nBob,30.0,1988-10-17,male"
print(data)
pd.read_csv(StringIO(data), names=["name", "age", "birth", "sex"]) #有时候可能只需要读取部分列的数据,可以指定参数 user_cols
pd.read_csv(StringIO(data), usecols=["name", "age"]) #空值填充为NaN
pd.read_csv(StringIO(data), keep_default_na=False)