【Pandas】Pandas中的DataFrame数据结构的部分用法

 由于最近涉及到数据分析,所以使用了很多关于pandas包的一些功能,持续总结如下:

文章目录

      • 01. 读写数据
        • 1.1 读取mysql中数据转DataFrame格式
        • 1.2 读取多个csv文件合并到同一个DataFrame中
        • 1.3 从DataFrame中读取行列
        • 1.4 遍历DataFrame
      • 02.统计方法
        • 2.1 统计个数
        • 2.2 分组求和
        • 2.3 根据其他列计算出新列的值
        • 2.4 统计每行特定值的个数
        • 2.5 关联
        • 2.6 分组取topN
      • 03.其他
        • 3.1 类型转换
        • 3.2 排序然后重新编号
        • 3.3 查找和替换
        • 3.4 填充缺失时间
        • 3.5 修改列名
        • 3.6 去重
        • 3.7 索引和列的相互转换
        • 3.8 行转为列
      • 04.计算
        • 4.1 前后行相减

01. 读写数据

1.1 读取mysql中数据转DataFrame格式

select_sql = """select * from sku_params_parsed order by product_time"""
results = db_client.commit_with_sql(select_sql)
column_names = ["spu", "sku_name", "is5G", "price", "battery", "thickness", "screen_size", "ram", "rom", "weight", "screen_refresh"]
df = pd.DataFrame(
    [[temp[2], temp[1], temp[17], temp[3],temp[8], temp[9], temp[10], temp[11], temp[12], temp[13], temp[14]] for temp in results],
    columns=column_names)

1.2 读取多个csv文件合并到同一个DataFrame中

header = [
    "cat_lvl5_name", "goods_name", "goods_id", "sale_channel_2", "sale_channel_name_2",
    "pay_cnt", "signed_cnt", "srv_return_cnt", "offline_return_cnt"
]
df_from_each_file = []
for home, _, files in os.walk(CURRENT_PATH + "/SalesData/1"):
    for filename in files:
        full_name = os.path.join(home, filename)
        # 读取csv文件
        temp_df = pd.read_csv(full_name, header=None)
        # 增加header
        temp_df.columns = header
        # 获取df的行数
        row = temp_df.shape[0]
        # 增加一列
        now = time.strftime("%Y-%m-%d", time.strptime(filename.replace(".csv", ""), "%Y%m%d"))
        temp_df['date'] = [now] * row
        df_from_each_file.append(temp_df)

# 多个csv文件读取后得到的dataframe进行合并
concatenated_df = pd.concat(df_from_each_file, ignore_index=True)

1.3 从DataFrame中读取行列

# loc,基于列label,可选取特定行(根据行index);
# iloc,基于行/列的序号;

# 读取指定列名的多列
df[['a', 'b', 'c']]

# 读取指定列号的多列,读取所有行的第2列到第20列
df.iloc[:, 2:20]
# 读取指定列名的,所有行
df.loc[:, ["a", "b"]]

# 读取指定行号的数据,读取所有猎的第2行到第20行的数据
df.iloc[2:20, :]
# 读取指定行号的指定列名的数据
df.loc[2:20, ['a', 'b']]

#取p_feature中不包含列名为index 的所有列
p_feature = p_feature.iloc[:, p_feature.columns != "index"]
# 包含
p_feature = p_feature.loc[:,p_feature.columns.isin(["index","授信编号"])]
# 加~ 变为不包含
p_feature = p_feature.loc[:,~p_feature.columns.isin(["index","授信编号"])]

1.4 遍历DataFrame

import pandas as pd
#读入数据
df = pd.read_table('d:/Users/chen_lib/Desktop/tmp.csv',sep=',', header='infer')
df.head()
 
-----------------result------------------
        mas  effectdate	 num
0	371379	2019-07-15	361
1	344985	2019-07-13	77
2	425090	2019-07-01	105
3	344983	2019-02-19	339
4	432430	2019-02-21	162
# 方法一:
for index, row in df.iterrows():
    print(index,row['mas'],row['num']) 
 

------------result---------------
0 371379 361
1 344985 77
2 425090 105
3 344983 339
4 432430 162

# 方法二
for row in df.itertuples():
    print(getattr(row, 'mas'), getattr(row, 'num')) # 输出每一行
 
 
-------------result-----------------
371379 361
344985 77
425090 105
344983 339
432430 162

# 方法三:
for index, row in df.iteritems():
    print(index,row[0],row[1],row[2])
 
 
-------------result------------------
masterhotelid 371379 344985 425090
effectdate 2019-07-15 2019-07-13 2019-07-01
quantity 361 77 105

02.统计方法

2.1 统计个数

# 统计各类出现的次数, 结果是 Series 格式,可以直接利用dict转换为字典形式
counts=df.value_counts()
print(counts)
# 统计个数大于1的行数
print(counts[counts>1])

# 统计符合某个范围的值的个数
# 注意这里不能使用and和or, 对应的应该使用 & 和 | 
df[(df["price"]>999) & (df["price"]<=1499)]["price"].count()
# 结果的类型是 numpy.int64,需要利用int强制转换为int类型

2.2 分组求和

# 根据date和sale_channel_name_2进行分组,然后对其他字段分别使用不同的聚合函数
# 由于group by 之后 分组依据会变成index,在保存的时候不会保存到excel,所以通过reset_index
# 重新进行index的划分
import numpy as np
tm_df = concatenated_df[concatenated_df["sale_channel_name_2"] == "天猫淘宝直营"].groupby(
    ['date', 'sale_channel_name_2']
).agg({'goods_id': np.max, 'sale_channel_2': np.max, "pay_cnt":np.sum,
       "signed_cnt":np.sum, "srv_return_cnt":np.sum, "offline_return_cnt":np.sum}).reset_index()

2.3 根据其他列计算出新列的值

# 根据signed_cnt、srv_return_cnt、offline_return_cnt三列的值计算出real_sales的值
# 主要依赖于 lambda 的匿名函数
# axis = 1,就会把一行数据作为Series的数据结构传入给自己实现的函数中,
# 我们在函数中实现对Series不同属性之间的计算,返回一个结果
tm_df["real_sales"] = tm_df.apply(
    lambda x: int(x.signed_cnt) - int(x.srv_return_cnt) - int(x.offline_return_cnt), axis = 1
)

2.4 统计每行特定值的个数

# 返回每行缺失值的总数
df.isnull().sum(axis=1)

# 返回每列缺失值的总数
df.isnull().sum(axis=0)

# 返回每行指定值的个数
active_30day_train_df['active_num'] = (active_30day_train_df == True).sum(axis=1)

2.5 关联

# how的方法有: left、right、outer、inner分别表示
# 只保留左表的所有数据、只保留右表的所有数据、保留两个表的所有信息、只保留两个表中公共部分的信息
result = pd.merge(left, right, how='left', on=['key1', 'key2'])

# 如果和表合并的过程中遇到有一列两个表都同名,但是值不同,合并的时候又都想保留下来,就可以用suffixes给每个表的重复列名增加后缀。
result = pd.merge(left, right, on='k', suffixes=['_l', '_r'])

2.6 分组取topN

# 整体思路是将分组标准转化为索引,然后利用head函数即可
# 直接取索引的topN如下
df.groupby("category").head(10)
# 先分组再取topN如下
count_with_category = df.groupby(["category", "tag_name"]).agg(
    {"count_num": np.sum}
).sort_values(by=["category", "count_num"], ascending=[False, False]).groupby("category").head(10)

03.其他

3.1 类型转换

# DataFrame一列统一转换为int类型
df['price'] = df['price'].apply(int)
# DataFrame一列先替换某些字符串后再统一转换为int类型
df['battery'] = df['battery'].str.replace("mAh", "").apply(int)
# 同时转换多列为数值型
data_df[["闪存", "内存", "价格", "厚度", "重量"]] = data_df[
    ["闪存", "内存", "价格", "厚度", "重量"]
].apply(pd.to_numeric)

3.2 排序然后重新编号

# 设置drop=True可以不保留原有的index列
concatenated_df = concatenated_df
.sort_values(['date', 'sale_channel_name_2'], ascending=[True, False])
.reset_index(drop=True)

3.3 查找和替换

# 查找sku_id列满足某个条件,然后替换source列为某个值
temp_df.loc[temp_df['sku_id'].str.contains('-'), 'source'] = 'tianmao'
# 查找sku_id列不满足某个条件,然后替换source列为某个值
temp_df.loc[~temp_df['sku_id'].str.contains('-'), 'source'] = 'tianmao'

# 查找concatenated_df的commentCount列中包含+的,nan用false代替
concatenated_df[concatenated_df["commentCount"].str.contains('\\+', na=False)]

# 替换某列(数字和字符串混合的列)中字符换中的+号,且保证不存在nan
mask = concatenated_df['commentCount'].apply(type) == str
concatenated_df['commentCount'] = concatenated_df['commentCount'].mask(
    mask, concatenated_df['commentCount'].str.replace("+", "")
    )

3.4 填充缺失时间

# 日期列转换为pandas的日期格式
temp_df['date'] = pd.to_datetime(temp_df["date"])
# 设置dataframe的索引为date
df_date = temp_df.set_index("date")
df_date = df_date.set_index(pd.to_datetime(df_date.index))
# 获取日期列的最小时间和最大时间, Timestamp格式
max_date = df['date'].max()
min_date = df['date'].min()
# 生成完整的日期序列
pdates = pd.date_range(start=min_date, end=max_date)
# 填充缺失索引,并填充默认值
df_date_new = df_date.reindex(pdates, fill_value=0)

3.5 修改列名

# 修改列名a,b为A、B。
df.columns = ['A','B']

# 只修改列名a为A
df.rename(columns={'a':'A'})

3.6 去重

# 根据某一列去重
concatenated_df.drop_duplicates(['goods_name'])

3.7 索引和列的相互转换

df.set_index('date', inplace=True) # column 改为 index
df.reset_index() # (all)index 改为 column

3.8 行转为列

参考地址:https://www.cnblogs.com/traditional/p/11967360.html

print(df)
"""
     姓名  科目   分数
0  古明地觉  语文   90
1  古明地觉  数学   95
2  古明地觉  英语   96
3  芙兰朵露  语文   87
4  芙兰朵露  数学   92
5  芙兰朵露  英语   98
6   琪露诺  语文   100
7   琪露诺  数学    9
8   琪露诺  英语   91
"""

# 注意此处也可以多级索引,用LIST形式,例如 index=["班级", "姓名"]
print(pd.pivot(df, index="姓名", columns="科目", values="分数"))
"""
科目    数学  英语   语文
姓名               
古明地觉  95  96   90
琪露诺    9  91  100
芙兰朵露  92  98   87
"""
# 可以看到上面这一步,就直接相当于df.set_index(["姓名", "科目"])["分数"].unstack()
# 然后再手动rename_axis、再reset_index即可
# 可以通过 rename_axis(index=, columns=) 来给坐标轴重命名
new_df = new_df.rename_axis(columns=None)
new_df = new_df.reset_index()
print(new_df)
"""
     姓名  数学  英语   语文
0  古明地觉  95  96   90
1   琪露诺   9   91  100
2  芙兰朵露  92  98   87
"""

# 如果我们是想将"姓名"变成列的话, 那么就指定columns="姓名"即可
print(pd.pivot(df, index="科目", columns="姓名", values="分数"))
"""
姓名  古明地觉  琪露诺  芙兰朵露
科目                 
数学    95    9    92
英语    96   91    98
语文    90  100    87
"""

04.计算

4.1 前后行相减

# 由于第一行是没有前一行的,所以一般需要跟 .fillna(0) 将第一行的结果转换为数字
df["daily_comment"] = (df["commentCount"] - df["commentCount"].shift(1)).fillna(0)

你可能感兴趣的:(Python基础,python,数据分析,pandas,DataFrame)