pandas数据处理(一)

Pandas 名字衍生自术语 "panel data"(面板数据)和 "Python data analysis"(Python 数据分析)
参考: https://pandas.pydata.org/ http://c.biancheng.net/pandas/plot.html

1. 简介

Pandas 的主要数据结构是 Series (一维数据)与 DataFrame(二维数据)。

Series 是一种类似于一维数组的对象,它由一组数据(各种Numpy数据类型)以及一组与之相关的数据标签(即索引)组成。

DataFrame 是一个表格型的数据结构,它含有一组有序的列,每列可以是不同的值类型(数值、字符串、布尔型值)。DataFrame 既有行索引也有列索引,它可以被看做由 Series 组成的字典(共同用一个索引)。

2. 安装以及简单使用

  1. 安装
pip install pandas
  1. 简单使用
# author: qlq
# date: 2022/8/17 18:09
# desc:
import pandas as pd
print(pd.__version__)

mydataset = {
  'sites': ["Google", "Runoob", "Wiki"],
  'number': [1, 2, 3]
}

myvar = pd.DataFrame(mydataset)

print(myvar)

结果:

1.4.3
    sites  number
0  Google       1
1  Runoob       2
2    Wiki       3

3. Series

Series 类似表格中的一个列(column),类似于一维数组,可以保存任何数据类型。

Series 由索引(index)和列组成,函数如下:

pandas.Series( data, index, dtype, name, copy)

参数说明:

data:一组数据(ndarray 类型)。

index:数据索引标签,如果不指定,默认从 0 开始。

dtype:数据类型,默认会自己判断。

name:设置名称。

copy:拷贝数据,默认为 False。

简单使用:

import pandas as pd

a = [1, 2, 3]
myvar = pd.Series(a)
print(myvar)
'''
0    1
1    2
2    3
dtype: int64
'''
# 0, 1, 2 列可以称为索引。 1, 2, 3 是数据。dtype: int64 是数据类型

'''
从上图可知,如果没有指定索引,索引值就从 0 开始,我们可以根据索引值读取数据:
我们可以指定索引值,如下实例:
'''
a2 = ["Google", "Runoob", "Wiki"]
myvar2 = pd.Series(a2, index = ["x", "y", "z"])
print(myvar2)
'''
x    Google
y    Runoob
z      Wiki
dtype: object
'''
print(myvar2["y"])
'''
Runoob
'''

'''
可以使用 key/value 对象,类似字典来创建 Series:
'''
sites = {1: "Google", 2: "Runoob", 3: "Wiki"}
myvar3 = pd.Series(sites)
print(myvar3)
'''
1    Google
2    Runoob
3      Wiki
dtype: object
'''

'''
从上图可知,字典的 key 变成了索引值。如果我们只需要字典中的一部分数据,只需要指定需要数据的索引即可,如下实例:
'''
sites2 = {1: "Google", 2: "Runoob", 3: "Wiki"}
myvar4 = pd.Series(sites2, index = [1, 2])
print(myvar4)
'''
1    Google
2    Runoob
dtype: object
'''

'''
设置 Series 名称参数:
'''
sites3 = {1: "Google", 2: "Runoob", 3: "Wiki"}
myvar5 = pd.Series(sites3, index = [1, 2], name="RUNOOB-Series-TEST" )
print(myvar5)
'''
1    Google
2    Runoob
Name: RUNOOB-Series-TEST, dtype: object
'''

4. DataFrame

​ DataFrame 是一个表格型的数据结构,它含有一组有序的列,每列可以是不同的值类型(数值、字符串、布尔型值)。DataFrame 既有行索引也有列索引,它可以被看做由 Series 组成的字典(共同用一个索引)。

​ 如下图:

构造方法如下:

pandas.DataFrame( data, index, columns, dtype, copy)

参数解释:

data:一组数据(ndarray、series, map, lists, dict 等类型)。

index:索引值,或者可以称为行标签。

columns:列标签,默认为 RangeIndex (0, 1, 2, …, n) 。

dtype:数据类型。

copy:拷贝数据,默认为 False。

简单使用:

# Pandas DataFrame 是一个二维的数组结构,类似二维数组。
import pandas as pd
data = [['Google',10],['Runoob',12],['Wiki',13]]
df = pd.DataFrame(data,columns=['Site','Age'],dtype=float)
print(df)
'''
常见属性和方法:
T	行和列转置。
axes	返回一个仅以行轴标签和列轴标签为成员的列表。
dtypes	返回每列数据的数据类型。
empty	DataFrame中没有数据或者任意坐标轴的长度为0,则返回True。
ndim	轴的数量,也指数组的维数。
shape	返回一个元组,表示了 DataFrame 维度。
size	DataFrame中的元素数量。
values	使用 numpy 数组表示 DataFrame 中的元素值。
head()	返回前 n 行数据。
tail()	返回后 n 行数据。
shift()	将行或列移动指定的步幅长度
'''
print(df.axes)
print(df.index)
print(df.ndim)
print(df.size)
print(df.values)

print("======1")
# 使用 ndarrays 创建,ndarray 的长度必须相同, 如果传递了 index,则索引的长度应等于数组的长度。如果没有传递索引,则默认情况下,索引将是range(n),其中n是数组长度
data1 = {'Site':['Google', 'Runoob', 'Wiki'], 'Age':[10, 12, 13]}
df1 = pd.DataFrame(data1)
print(df1)

print("======2")
# 可以使用字典(key/value),其中字典的 key 为列名。没有对应的部分数据为 NaN。
data2 = [{'a': 1, 'b': 2},{'a': 5, 'b': 10, 'c': 20}]
df2 = pd.DataFrame(data2)
print(df2)

print("======3")
# 可以使用 loc 属性返回指定行的数据,如果没有设置索引,第一行索引为 0,第二行索引为 1,以此类推
data3 = {
  "calories": [420, 380, 390],
  "duration": [50, 40, 45]
}
# 数据载入到 DataFrame 对象
df3 = pd.DataFrame(data3)
print(df3)
# 返回第一行
print(df3.loc[0])
# 返回第二行
print(df3.loc[1])
# 返回第一行和第二行
print(df3.loc[[0, 1]])

print("======4")
# 指定索引值,使用 loc 属性返回指定索对应到某一行
data4 = {
  "calories": [420, 380, 390],
  "duration": [50, 40, 45]
}
df4 = pd.DataFrame(data4, index = ["day1", "day2", "day3"])
print(df4)
# 指定索引
print(df4.loc["day2"])

结果:

     Site   Age
0  Google  10.0
1  Runoob  12.0
2    Wiki  13.0
[RangeIndex(start=0, stop=3, step=1), Index(['Site', 'Age'], dtype='object')]
RangeIndex(start=0, stop=3, step=1)
2
6
[['Google' 10.0]
 ['Runoob' 12.0]
 ['Wiki' 13.0]]
======1
     Site  Age
0  Google   10
1  Runoob   12
2    Wiki   13
======2
   a   b     c
0  1   2   NaN
1  5  10  20.0
======3
   calories  duration
0       420        50
1       380        40
2       390        45
calories    420
duration     50
Name: 0, dtype: int64
calories    380
duration     40
Name: 1, dtype: int64
   calories  duration
0       420        50
1       380        40
======4
      calories  duration
day1       420        50
day2       380        40
day3       390        45
calories    380
duration     40
Name: day2, dtype: int64

5. 操作csv、excel

比如nba.csv 格式如下:

Name,Team,Number,Position,Age,Height,Weight,College,Salary
Avery Bradley,Boston Celtics,0.0,PG,25.0,6-2,180.0,Texas,7730337.0
Jae Crowder,Boston Celtics,99.0,SF,25.0,6-6,235.0,Marquette,6796117.0
John Holland,Boston Celtics,30.0,SG,27.0,6-5,205.0,Boston University,
R.J. Hunter,Boston Celtics,28.0,SG,22.0,6-5,185.0,Georgia State,1148640.0
,,,,,,,,

测试代码:

# desc:
import pandas as pd
df = pd.read_csv('E:/nba.csv')
# to_string() 用于返回 DataFrame 类型的数据,如果不使用该函数,则输出结果为数据的前面 5 行和末尾 5 行,中间部分以 ... 代替
print(df.to_string())

print("======1")
# info() 方法返回表格的一些基本信息:
print(df.info())
print("======2")
# head( n ) 和 tail(n) 查看指定开头和结尾数据。 默认n=5
print(df.head())
print("======3")
print(df.tail())

# to_XXX 转储文件
df.to_csv("E:/nba1.csv")
df.to_excel("E:/nba1.xlsx")

结果:

            Name            Team  Number Position   Age Height  Weight            College     Salary
0  Avery Bradley  Boston Celtics     0.0       PG  25.0    6-2   180.0              Texas  7730337.0
1    Jae Crowder  Boston Celtics    99.0       SF  25.0    6-6   235.0          Marquette  6796117.0
2   John Holland  Boston Celtics    30.0       SG  27.0    6-5   205.0  Boston University        NaN
3    R.J. Hunter  Boston Celtics    28.0       SG  22.0    6-5   185.0      Georgia State  1148640.0
4            NaN             NaN     NaN      NaN   NaN    NaN     NaN                NaN        NaN
======1
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 5 entries, 0 to 4
Data columns (total 9 columns):
 #   Column    Non-Null Count  Dtype  
---  ------    --------------  -----  
 0   Name      4 non-null      object 
 1   Team      4 non-null      object 
 2   Number    4 non-null      float64
 3   Position  4 non-null      object 
 4   Age       4 non-null      float64
 5   Height    4 non-null      object 
 6   Weight    4 non-null      float64
 7   College   4 non-null      object 
 8   Salary    3 non-null      float64
dtypes: float64(4), object(5)
memory usage: 488.0+ bytes
None
======2
            Name            Team  Number  ... Weight            College     Salary
0  Avery Bradley  Boston Celtics     0.0  ...  180.0              Texas  7730337.0
1    Jae Crowder  Boston Celtics    99.0  ...  235.0          Marquette  6796117.0
2   John Holland  Boston Celtics    30.0  ...  205.0  Boston University        NaN
3    R.J. Hunter  Boston Celtics    28.0  ...  185.0      Georgia State  1148640.0
4            NaN             NaN     NaN  ...    NaN                NaN        NaN

[5 rows x 9 columns]
======3
            Name            Team  Number  ... Weight            College     Salary
0  Avery Bradley  Boston Celtics     0.0  ...  180.0              Texas  7730337.0
1    Jae Crowder  Boston Celtics    99.0  ...  235.0          Marquette  6796117.0
2   John Holland  Boston Celtics    30.0  ...  205.0  Boston University        NaN
3    R.J. Hunter  Boston Celtics    28.0  ...  185.0      Georgia State  1148640.0
4            NaN             NaN     NaN  ...    NaN                NaN        NaN

[5 rows x 9 columns]

同理也有操作excel的相关API

import pandas as pd
df = pd.read_excel('E:/nba1.xlsx')
# to_string() 用于返回 DataFrame 类型的数据,如果不使用该函数,则输出结果为数据的前面 5 行和末尾 5 行,中间部分以 ... 代替
print(df.to_string())

6. 操作JSON

nested_list.json 代码如下:

{
    "school_name": "ABC primary school",
    "class": "Year 1",
    "students": [
    {
        "id": "A001",
        "name": "Tom",
        "math": 60,
        "physics": 66,
        "chemistry": 61
    },
    {
        "id": "A002",
        "name": "James",
        "math": 89,
        "physics": 76,
        "chemistry": 51
    },
    {
        "id": "A003",
        "name": "Jenny",
        "math": 79,
        "physics": 90,
        "chemistry": 78
    }]
}

简单使用:

# desc:
import json

import pandas as pd
df = pd.read_json('E:/nested_list.json')
print(df.to_string())

print("======1")
json_path = 'E:/nested_list.json'
# 使用 Python JSON 模块载入数据
# 展平数据
with open(json_path,'r') as f:
    data = json.loads(f.read())
df_nested_list = pd.json_normalize(data, record_path =['students'])
print(df_nested_list)

print("======2")
# 使用 Python JSON 模块载入数据
with open(json_path,'r') as f:
    data = json.loads(f.read())
# 展平数据。
# json_normalize() 使用了参数 record_path 并设置为 ['students'] 用于展开内嵌的 JSON 数据 students
# 使用 meta 参数来显示这些元数据
df_nested_list = pd.json_normalize(
    data,
    record_path =['students'],
    meta=['school_name', 'class']
)
print(df_nested_list)

结果:

          school_name   class                                                                     students
0  ABC primary school  Year 1    {'id': 'A001', 'name': 'Tom', 'math': 60, 'physics': 66, 'chemistry': 61}
1  ABC primary school  Year 1  {'id': 'A002', 'name': 'James', 'math': 89, 'physics': 76, 'chemistry': 51}
2  ABC primary school  Year 1  {'id': 'A003', 'name': 'Jenny', 'math': 79, 'physics': 90, 'chemistry': 78}
======1
     id   name  math  physics  chemistry
0  A001    Tom    60       66         61
1  A002  James    89       76         51
2  A003  Jenny    79       90         78
======2
     id   name  math  physics  chemistry         school_name   class
0  A001    Tom    60       66         61  ABC primary school  Year 1
1  A002  James    89       76         51  ABC primary school  Year 1
2  A003  Jenny    79       90         78  ABC primary school  Year 1

7. 数据清洗

主要包括空值处理、错误数据处理、重复数据处理。

例如数据如下 property-data.csv

上表包含了四种空数据:

  • n/a
  • NA
  • na

1. 空值处理

使用 dropna() 方法,语法格式如下:

DataFrame.dropna(axis=0, how='any', thresh=None, subset=None, inplace=False)

axis:默认为 0,表示逢空值剔除整行,如果设置参数 axis=1 表示逢空值去掉整列。
how:默认为 'any' 如果一行(或一列)里任何一个数据有出现 NA 就去掉整行,如果设置 how='all' 一行(或列)都是 NA 才去掉这整行。
thresh:设置需要多少非空值的数据才可以保留下来的。
subset:设置想要检查的列。如果是多个列,可以使用列名的 list 作为参数。
inplace:如果设置 True,将计算得到的值直接覆盖之前的值并返回 None,修改的是源数据。

1. 检测空值

Pandas 把 n/a 和 NA 当作空数据,na 不是空数据。 可以通过自己指定然后设置为空的值。

import pandas as pd
csv_path = 'E:/property-data.csv'
df = pd.read_csv(csv_path)
print (df['NUM_BEDROOMS'])
#  isnull() 判断各个单元格是否为空
# 把 n/a 和 NA 当作空数据,na 不是空数据
print (df['NUM_BEDROOMS'].isnull())

# 自定义为空值的值
print("======1")
missing_values = ["n/a", "na", "--"]
df1 = pd.read_csv(csv_path, na_values = missing_values)
print (df1['NUM_BEDROOMS'])
print (df1['NUM_BEDROOMS'].isnull())

结果:

0      3
1      3
2    NaN
3      1
4      3
5    NaN
6      2
7      1
8     na
Name: NUM_BEDROOMS, dtype: object
0    False
1    False
2     True
3    False
4    False
5     True
6    False
7    False
8    False
Name: NUM_BEDROOMS, dtype: bool
======1
0    3.0
1    3.0
2    NaN
3    1.0
4    3.0
5    NaN
6    2.0
7    1.0
8    NaN
Name: NUM_BEDROOMS, dtype: float64
0    False
1    False
2     True
3    False
4    False
5     True
6    False
7    False
8     True
Name: NUM_BEDROOMS, dtype: bool

2. 删除包含空值的行

import pandas as pd
csv_path = 'E:/property-data.csv'

# 删除包含空数据的行
# 默认情况下,dropna() 方法返回一个新的 DataFrame,不会修改源数据。 如果要修改源数据 DataFrame, 可以使用 inplace = True 参数:
df = pd.read_csv(csv_path)
new_df = df.dropna()
print(new_df.to_string())

结果:

           PID  ST_NUM    ST_NAME OWN_OCCUPIED NUM_BEDROOMS NUM_BATH SQ_FT
0  100001000.0   104.0     PUTNAM            Y            3        1  1000
1  100002000.0   197.0  LEXINGTON            N            3      1.5    --
8  100009000.0   215.0    TREMONT            Y           na        2  1800

3. 移除指定列有空值的行

import pandas as pd

csv_path = 'E:/property-data.csv'
df = pd.read_csv(csv_path)
df.dropna(subset=['ST_NUM'], inplace = True)
print(df.to_string())

结果:

           PID  ST_NUM    ST_NAME OWN_OCCUPIED NUM_BEDROOMS NUM_BATH SQ_FT
0  100001000.0   104.0     PUTNAM            Y            3        1  1000
1  100002000.0   197.0  LEXINGTON            N            3      1.5    --
3  100004000.0   201.0   BERKELEY           12            1      NaN   700
4          NaN   203.0   BERKELEY            Y            3        2  1600
5  100006000.0   207.0   BERKELEY            Y          NaN        1   800
7  100008000.0   213.0    TREMONT            Y            1        1   NaN
8  100009000.0   215.0    TREMONT            Y           na        2  1800

4. fillna 方法替换空值

import pandas as pd

csv_path = 'E:/property-data.csv'
df = pd.read_csv(csv_path)
df.fillna('12345', inplace = True)
# 也可以指定列
# df['PID'].fillna(12345, inplace = True)
print(df.to_string())

结果:

           PID ST_NUM     ST_NAME OWN_OCCUPIED NUM_BEDROOMS NUM_BATH  SQ_FT
0  100001000.0  104.0      PUTNAM            Y            3        1   1000
1  100002000.0  197.0   LEXINGTON            N            3      1.5     --
2  100003000.0  12345   LEXINGTON            N        12345        1    850
3  100004000.0  201.0    BERKELEY           12            1    12345    700
4        12345  203.0    BERKELEY            Y            3        2   1600
5  100006000.0  207.0    BERKELEY            Y        12345        1    800
6  100007000.0  12345  WASHINGTON        12345            2   HURLEY    950
7  100008000.0  213.0     TREMONT            Y            1        1  12345
8  100009000.0  215.0     TREMONT            Y           na        2   1800

5. 均值、中位数、众数

mean()median()mode() 方法计算列的均值(所有值加起来的平均值)、中位数值(排序后排在中间的数)和众数(出现频率最高的数)

一般用上面的数来替换空值。

import pandas as pd

csv_path = 'E:/property-data.csv'
df = pd.read_csv(csv_path)
# 均值
print(df["ST_NUM"].mean())
# 中位数
print(df["ST_NUM"].median())
# 众数
print(df["ST_NUM"].mode())

结果:

191.42857142857142
203.0
0    104.0
1    197.0
2    201.0
3    203.0
4    207.0
5    213.0
6    215.0

2. 清洗错误数据

1. 定位数据然后修改

import pandas as pd

person = {
  "name": ['Google', 'Runoob' , 'Taobao'],
  "age": [50, 40, 12345]    # 12345 年龄数据是错误的
}
df = pd.DataFrame(person)
df.loc[2, 'age'] = 30 # 修改数据
print(df.to_string())

结果:

     name  age
0  Google   50
1  Runoob   40
2  Taobao   30

2. 通过条件修改

import pandas as pd

person = {
  "name": ['Google', 'Runoob' , 'Taobao'],
  "age": [50, 200, 12345]
}
# 将 age 大于 120 的设置为 120:
df = pd.DataFrame(person)
for x in df.index:
  if df.loc[x, "age"] > 120:
    df.loc[x, "age"] = 120

print(df.to_string())

3. 删除错误的行数据

import pandas as pd

person = {
  "name": ['Google', 'Runoob' , 'Taobao'],
  "age": [50, 200, 12345]
}
# 将 age 大于 120 的数据删除
df = pd.DataFrame(person)
for x in df.index:
  if df.loc[x, "age"] > 120:
    df.drop(x, inplace = True)

print(df.to_string())

3. 重复数据处理

清洗重复数据,可以使用 duplicated()drop_duplicates() 方法

如果对应的数据是重复的,duplicated() 会返回 True,否则返回 False。

  1. 检测重复数据
import pandas as pd
person = {
  "name": ['Google', 'Runoob', 'Runoob', 'Taobao'],
  "age": [50, 40, 40, 23]
}
df = pd.DataFrame(person)
print(df.to_string())
print("======1")
print(df.duplicated())

结果:

     name  age
0  Google   50
1  Runoob   40
2  Runoob   40
3  Taobao   23
======1
0    False
1    False
2     True
3    False
dtype: bool
  1. 删除重复数据
import pandas as pd
person = {
  "name": ['Google', 'Runoob', 'Runoob', 'Taobao', 'JD'],
  "age": [50, 40, 40, 23, 50]
}
df = pd.DataFrame(person)

print(df.to_string())
print("======1")
# 按全部的列去重
df.drop_duplicates(inplace = True)
print(df.to_string())
print("======1")
# 按指定的列进行去重
df.drop_duplicates(subset= ['age'], inplace = True)
print(df.to_string())

结果:

     name  age
0  Google   50
1  Runoob   40
2  Runoob   40
3  Taobao   23
4      JD   50
======1
     name  age
0  Google   50
1  Runoob   40
3  Taobao   23
4      JD   50
======1
     name  age
0  Google   50
1  Runoob   40
3  Taobao   23
posted @ 2022-08-18 23:06  QiaoZhi  阅读(279)  评论(0编辑  收藏  举报