新建表
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=1
和 ascending=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
这种方式实现关联。相比 merge
,join
这种方式有以下几个不同:
- 默认参数
on=None
,表示关联时使用左边和右边的索引作为键,设置参数on
可以指定的是关联时左边的所用到的键名 - 左边和右边字段名称重复时,通过设置参数
lsuffix
和rsuffix
来解决。
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)