使用Pandas处理.csv等表格文件

Pandas 是Python的核心数据分析支持库,提供了快速、灵活、明确的数据结构,旨在简单、直观地处理关系型、标记型数据。Pandas常用于处理带行列标签的矩阵数据、与 SQL 或 Excel 表类似的表格数据,应用于金融、统计、社会科学、工程等领域里的数据整理与清洗、数据分析与建模、数据可视化与制表等工作。

数据类型:Pandas 不改变原始的输入数据,而是复制数据生成新的对象,有普通对象构成的一维数组成为Series,由Series构成的二维数组表称为DataFrame,其行被称为index,列为Column

安装:如果使用anaconda集成环境则会自动安装numpy、scipy、pandas等数据科学包,也可以通过python包管理工具安装pandas:pip install pandas

1、数据对象的创建

通过Series()包裹一维数组可以创建Series对象,其中数组的元素可以是各种类型。

通过DataFrame()包裹二维数组可以创建一个DataFrame对象,可以通过参数indexcolumns指定行标签和列标签。也可以通过python的字典类型初始化DataFrame,其键名默认为列标签

import pandas as pd
import numpy as np

# 通过一维数组初始化Series
s = pd.Series([1, 2.0, np.nan, 'test'])
print(s)
'''
0       1
1       2
2     NaN
3    test
dtype: object
'''

# 通过二维数组初始化DataFrame
arr = np.random.randn(6, 4)
arr_df = pd.DataFrame(arr, index=np.arange(1, 7), columns=list('ABCD'))
print(arr_df)
'''
          A         B         C         D
1 -0.085417 -0.816502  1.495134 -0.277742
2  1.657144 -0.203346  0.631930 -1.182239
3 -2.303923 -0.535696  1.315379  0.129682
4  0.133198 -0.239664 -2.004494  0.119965
5 -1.454717  2.114255 -0.538678 -0.580361
6 -0.759183  0.141554 -0.243270  2.840325
'''

# 通过字典dict初始化DataFrame
dic = {'A': 1.,
       'B': pd.Timestamp('20130102'),
       'C': pd.Series(1, index=list(range(4)), dtype='float32'),
       'D': np.array([3] * 4, dtype='int32'),
       'E': pd.Categorical(["test", "train", "test", "train"])
       }
dic_df = pd.DataFrame(dic)
print(dic_df)
'''
     A          B    C  D      E
0  1.0 2013-01-02  1.0  3   test
1  1.0 2013-01-02  1.0  3  train
2  1.0 2013-01-02  1.0  3   test
3  1.0 2013-01-02  1.0  3  train
'''

注意到在使用“=”传递或选择DataFrame时,产生的使原数据的引用,修改引用原数据也会发生改变。
可以使用copy()创建一个新的数据,这样对副本的任何操作不会影响原数据。如果数据中含有对象,那么copy()会创建新的内存保存对象,但对象的具体值仍然是引用原对象,这就是浅拷贝。若希望拷贝对象的同时拷贝值,可以采用深拷贝,这时需指定属性deep=True。有的时候我们直接在原DataFrame上操作数据会报错 如下,这时候我们需要在原Dataframe后加上.copy()生成副本再进行操作。

SettingWithCopyWarning: A value is trying to be set on a copy of a slice from a DataFrame

df = pd.DataFrame({'A': [1, 2],
                   'B': [3, 4]})
row_cp = df.iloc[1].copy()
row_cp['A'] = 6  # 对副本修改,原来的df不会改变
print(df)

row = df.iloc[1]
row['A'] = 5    # 修改引用,原来的df随之发生改变
print(df)
'''
   A  B
0  1  3
1  2  4
   A  B
0  1  3
1  5  4
'''

2、查看数据

函数head(n)可以查看DataFrame前n行的数据,tail(n)查看倒数n行的数据

index()查看DataFrame的行标签,columns显示列标签

describe()按列显示数据的统计信息,包括计数、均值、方差、最小最大值等。

函数mean()显示所有列的均值,mean(1)显示所有行的均值

sum()求所有列的和,sum(1)求所有行的和

DataFrame有一个empty属性用于判断是否为空,若为空则返回True

arr = np.random.randn(6, 4)
df = pd.DataFrame(arr, index=np.arange(1, 7), columns=list('ABCD'))
print(df.head(3))
print(df.index)
print(df.describe())

'''
# 查看前三行数据
A         B         C         D
1  3.260449 -0.619396  0.070877  1.586914
2 -0.529708  0.071917 -1.919316  1.845727
3 -1.005765  2.176579 -0.323483 -1.295067
# 查看行标签
Int64Index([1, 2, 3, 4, 5, 6], dtype='int64')
# 查看统计信息
              A         B         C         D
count  6.000000  6.000000  6.000000  6.000000
mean  -0.184606 -0.487184  0.079433  0.855810
std    1.721394  1.800460  1.379498  1.128764
min   -1.443635 -3.091446 -1.919316 -1.295067
25%   -0.967105 -1.430192 -0.281188  0.778729
50%   -0.694488 -0.273739 -0.041713  1.150944
75%   -0.531744  0.197755  0.355731  1.508475
max    3.260449  2.176579  2.352142  1.845727
'''

3、数据的选择

可以像python的list一样直接对DataFrame对象进行切片,选取列或者行,

# 选取一个列A,等价于df['A']
print(df.A)
# 选取第1到第3行,行下标从0开始
print(df[1:3])

'''
# 标签为A的那一列
1    0.644427
2    0.643149
3    1.374668
4   -0.154465
5   -0.338085
6   -1.989284
Name: A, dtype: float64
# 第1~3行
          A         B         C         D
2  0.643149  1.769001 -0.166028 -0.036854
3  1.374668 -0.118593 -0.202222  0.308353
'''

通过loc[]方法可以通过具体的标签值对DataFrame的一行、一列、几行几列进行选择

# 取出行标签为2的那一行
print(df.loc[2])
# 取出行标签为1~3,列标签为'A','B'的内容
print(df.loc[1:3, ['A', 'B']])
# 获取行标签为1,列标签为'A'的具体值,等价于df.at[1,'A']
print(df.loc[1, 'A'])

'''
# 标签为2的一行
A    0.681469
B   -0.053046
C   -1.384877
D   -0.447700
Name: 2, dtype: float64
# 标签为1~3,列标签为'A','B'的内容
          A         B
1  0.710907 -0.950896
2  0.681469 -0.053046
3  0.781981  0.123072
# 行标签为1,列标签为'A'的具体值
0.7109074858947351
'''

除了通过行列标签来进行取值以外,还可以通过行列的数组的位置进行取值,其方法名为iloc[]

# 取出第一行,行下标从0开始
print(df.iloc[0])
# 显示第1,2,4行的第0,2列
print(df.iloc[[1, 2, 4], [0, 2]])
# 显示第1行第1列的具体值,等价于df.iat[1,1]
print(df.iloc[1, 1])

还可以根据True/False确定是否选择数据,例如选择所有指定字段>0、等于指定值的数据行

# 输出A那一列大于0的所有行
print(df[df.A > 0])

df['E'] = ['one', 'one', 'two', 'three', 'four', 'three']
# 选择E的值为two的行
print(df[df['E'] == 'two'])
# 输出E那一列存在two、four的所有行
print(df[df['E'].isin(['two', 'four'])])

'''
          A         B         C         D
3  0.168998 -0.732362 -0.098542  0.413128
5  0.513677 -0.163231 -0.098037 -0.606693

          A         B         C         D     E
3  0.168998 -0.732362 -0.098542  0.413128   two

          A         B         C         D     E
3  0.168998 -0.732362 -0.098542  0.413128   two
5  0.513677 -0.163231 -0.098037 -0.606693  four
'''

4、操作数据

通过insert()方法可以实现在指定位置插入一列,也可以直接将一个数组赋值给DataFrame,这将默认添加到最后一列

可以通过之前的选择方法loc、iloc找到指定的行列,然后直接赋值,如果该位置存在数据则会修改,否则添加

通过iterrows()方法可以对DataFrame进行行遍历,在每一行通过关键字或列名操作每一个具体数据

通过drop()方法删除指定的数据,index属性指定删除的行,columns指定删除的列,drop_duplicates()指定删除重复的数据。

pandas对数据的操作不回在原数据表上生效,需要一个左值来接收操作的结果。如果希望在原数据上进行操作,需要指定属性inplace=True

df = pd.DataFrame(data = [['lisa','f',22],['joy','f',22],['tom','m',21]],
                  index = [1,2,3],columns = ['name','sex','age'])
citys = ['ny','zz','xy']
#在第0列,加上column名称为city,值为citys的数值。
df.insert(0,'city',citys)
jobs = ['student','AI','teacher']
# 默认在df最后一列加上column名称为job,值为jobs的数据。
df['job'] = jobs
# 若df中没有index为“4”的这一行的话,则添加,否则修改
df.loc[4] = ['zz', 'mason', 'm', 24, 'engineer']
print(df)
'''
  city   name sex age       job
1   ny   lisa   f  22   student
2   zz    joy   f  22        AI
3   xy    tom   m  21   teacher
4   zz  mason   m  24  engineer
'''

# 修改某一列
df['age'] += 1
print(df)
'''
   name sex  age
1  lisa   f   23
2   joy   f   23
3   tom   m   22
'''

# 遍历每一行
for index,rows in df.iterrows():
    print(index,rows)
'''
1 name    lisa
sex        f
age       22
Name: 1, dtype: object
2 name    joy
sex       f
age      22
Name: 2, dtype: object
3 name    tom
sex       m
age      21
Name: 3, dtype: object
'''

# 删除行标签为1的行
dp=df.drop(index=1)
print(dp)
'''
  city   name sex age       job
2   zz    joy   f  22        AI
3   xy    tom   m  21   teacher
4   zz  mason   m  24  engineer
'''
# 在原数据集上删除列标签为sex的列
df.drop(columns=['sex'],inplace=True)
print(df)
'''
  city   name age       job
1   ny   lisa  22   student
2   zz    joy  22        AI
3   xy    tom  21   teacher
4   zz  mason  24  engineer
'''

# 在原数据集上删除age列重复的数据,只保留第一个
df.drop_duplicates(subset='age', keep='first', inplace=True)
print(df)
'''
   name sex  age
1  lisa   f   22
3   tom   m   21
'''

对DataFrame进行转置操作,调用.T

sort_index(axis=1, ascending=False)对数据进行排序,axis=0代表按行标签排序,axis=1代表按列标签排序

sort_values(by='A')按某一列的值对数据进行排序,这里是按列标签为A的

apply()函数对DataFrame的每一行应用函数

set_index("col")可以设置DataFrame的索引列为指定的col。

reset_index()将原来的索引添加为列,并新增一个从0开始的数字作为索引,指定drop=True将丢弃原索引。

特别注意的是上面的操作需要左值来接收修改后的结果,不会直接修改原来的DataFrame。

# 数据转置
print(df.T)
'''
         1         2         3         4         5         6
A -1.176180 -1.301768  0.907088 -1.528101  1.098978 -1.280193
B -0.461954 -0.749642  1.169118 -0.297765  0.531088 -0.999842
C -1.715094 -0.512856  0.511861 -0.247240  1.696772 -0.902995
D  1.336999  0.209091  2.254337  0.649625 -0.049886 -1.514815
'''

# 按列标签倒序
si=df.sort_index(axis=1, ascending=False)
print(si)
'''
        D         C         B         A
1  1.336999 -1.715094 -0.461954 -1.176180
2  0.209091 -0.512856 -0.749642 -1.301768
3  2.254337  0.511861  1.169118  0.907088
4  0.649625 -0.247240 -0.297765 -1.528101
5 -0.049886  1.696772  0.531088  1.098978
6 -1.514815 -0.902995 -0.999842 -1.280193
'''

# 按列A的值递增对行排序
sv=df.sort_values(by='A')
print(sv)
'''
        A         B         C         D
4 -1.528101 -0.297765 -0.247240  0.649625
2 -1.301768 -0.749642 -0.512856  0.209091
6 -1.280193 -0.999842 -0.902995 -1.514815
1 -1.176180 -0.461954 -1.715094  1.336999
3  0.907088  1.169118  0.511861  2.254337
5  1.098978  0.531088  1.696772 -0.049886
'''

# 应用匿名函数,用每一列最大值减去最小值
df.apply(lambda x: x.max() - x.min())
print(df)
'''
A    2.073961
B    2.671590
C    1.785291
D    0.000000
F    4.000000
dtype: float64
'''

panda的concat函数可以将两个相同类型的DataFrame在行的维度上进行拼接

merge()函数可以将不同DataFrame按列拼接

append()函数可以在DataFrame的结尾追加,其索引值不会改变,如果希望追加之后重排索引值,需指定属性ignore_index=True,注意需要用左值来接收append后的结果

# 将第一行和最后一行拼接
print(pd.concat([df[:1], df[-2:-1]]))
'''
# 按行拼接
          A         B         C         D
1 -0.527221 -0.754650 -2.385270 -2.569586
5  0.054059  1.443911 -0.240856 -1.501045
'''

# 将第4行追加到结尾,索引值不变
df = df.append(df.iloc[3])
print(df)
'''
          A         B         C         D
1 -0.527221 -0.754650 -2.385270 -2.569586
2  2.123332 -0.013431 -0.574359 -0.548838
3 -0.244057 -0.267805  1.089026 -0.022174
4 -0.789228  1.171906  0.526318  0.046655
5  0.054059  1.443911 -0.240856 -1.501045
6  0.756844  0.623305 -0.597299  0.034326
4 -0.789228  1.171906  0.526318  0.046655
'''

# 将两个DataFrame按列拼接
df1 = pd.DataFrame({'row1': ['foo', 'bar'], 'row2': [1, 2]})
df2 = pd.DataFrame({'row1': ['foo', 'bar'], 'row3': [4, 5]})
print(pd.merge(df1, df2))
'''
  row1  row2  row3
0  foo     1     4
1  bar     2     5
'''

groupby()可以数据按列进行分组,分组后的结果可以使用for循环进行迭代,迭代中每个分组是一个(index,DataFrame)元组,可以对其中的DataFrame作进一步操作。之后可以直接将sum()mean()等聚合函数用于分组结果上,也可用agg()对指定列使用指定的聚合函数。

stack()可以将多列的数据压缩为两列显示

df = pd.DataFrame({'A': ['foo', 'bar', 'foo', 'bar'],
                   'B': ['one', 'two', 'one', 'three'],
                   'C': np.random.randn(4),
                   'D': np.random.randn(4)})
# 按A、B两列进行分组
dg=df.groupby(['A', 'B'])
for (index,df) in dg:
       print(df)
'''
     A      B         C        D
3  bar  three  0.895239  0.17702
     A    B         C         D
1  bar  two -0.391467  2.485707
     A    B         C         D
0  foo  one -1.516292  0.108226
2  foo  one  1.909878 -1.469921
                  C         D
'''
# 对分组求和
print(dg.sum())
'''
A   B                        
bar three  0.895239  0.177020
    two   -0.391467  2.485707
foo one    0.393586 -1.361695
'''
# 按A列进行分组并求C的最大最小值
dg = df.groupby(['A']).agg({'C': ['max', 'min']})
print(dg)
'''
            C          
          max       min
A                      
bar  1.466636  0.178420
foo  0.782000 -1.246935
'''

# 压缩
print(df.stack())
'''
0  A         foo
   B         one
   C    -1.51629
   D    0.108226
2  A         foo
   B         one
   C     1.90988
   D    -1.46992
'''

shift()可以将一列数据平移指定位置,diff()用原数据减去平移后的数据

df = pd.DataFrame([1, 2, 3, 4, 5])
print(df.shift(2))  # 向后平移两个位置
print(df.diff(2))   # 原数据减去平移两位后的差
'''
     0
0  NaN
1  NaN
2  1.0
3  2.0
4  3.0
     0
0  NaN
1  NaN
2  2.0
3  2.0
4  2.0
'''

Pandas主要使用值np.nan来表示缺失的数据。可以使用dropna(how='any')方法来删除所有存在空值的行,dropna(axis=1)删除存在空值的列。fillna(value=x)用指定值x填充所有的空值。

5、时间索引

pandas中通过Timestamp对象来处理时间类型,可以通过Timestamp()方法创建一个时间对象,或通过to_datetime()可以将字符串转化为Timestamp对象,从而根据时间来排序。由于Timestamp是从Python标准库的datetime类继承过来的,所以其用法相似。

data = pd.DataFrame()
time_str = ['2020-03-24T22:24:01.000Z', '2020-03-24T22:26:11.000Z', '2020-03-24T22:25:11.000Z']
data['timestamp'] = pd.to_datetime(time_str, format='%Y-%m-%dT%H:%M:%S.%fZ')	# 格式化时间字符串
data.sort_values(by=['timestamp'], inplace=True, ascending=True)
print(data)
'''
            timestamp
0 2020-03-24 22:24:01
2 2020-03-24 22:25:11
1 2020-03-24 22:26:11
'''

两个Timestamp对象作差得到的是时间差对象Timedelta,也可以通过Timedelta(days=0, seconds=0, microseconds=0, milliseconds=0, minutes=0, hours=0, weeks=0)来创建。同样地它也是继承自python标准库datetime。
它具有两个属性daysseconds,对应时间间隔是几天零几秒。Timedelta和Timestamp相加可以得到另一个Timestamp对象。

time_list = ['2020-06-01 12:00', '2020-06-02 13:00', '2020-06-05 15:00']
time_list = pd.to_datetime(time_list, format="%Y-%m-%d %H:%M")
time_delta = time_list[1] - time_list[0]  # 作差得到Timedelta
print('时间间隔:', time_delta, '其中包括', time_delta.days, '天+', time_delta.seconds, '秒')
'''
时间间隔: 1 days 01:00:00 其中包括 1 天+ 3600 秒
'''
time_delta = pd.Timedelta(days=1, hours=2, minutes=30)  # 创建Timedelta对象
print(time_list[2] + time_delta)    # 相加得Timestamp
'''
2020-06-06 17:30:00
'''

pandas提供了DatetimeIndex对象用于将时间序列当作索引来操作数据。首先使用DatetimeIndex()可以将一维数组序列转化为DatetimeIndex对象。通过操作时间索引可以像数字索引那样进行数据的选择、切片操作。

# 创建时间戳序列
date_index = pd.DatetimeIndex(['4/1/2019','4/2/2019','4/2/2019','4/2/2019','4/3/2019'])
# 将序列设为索引
ts = pd.Series(np.arange(5),index=date_index)
print(ts)
'''
2019-04-01    0
2019-04-02    1
2019-04-02    2
2019-04-02    3
2019-04-03    4
dtype: int32
'''
# 按照时间索引对数据进行选择
print(ts['2019-4-2'])
'''
2019-04-02    1
2019-04-02    2
2019-04-02    3
dtype: int32
'''
# 按时间切片
print(ts['2019-4-1':'2019-4-2'])
'''
2019-04-01    0
2019-04-02    1
2019-04-02    2
2019-04-02    3
dtype: int32
'''

除此之外还可以通过period_range()/date_range()来创建时间序列,该方法可以接收起始时间、中止时间、时间频率、时间长度作为参数,这四个参数至少要有三个才能确定一个时间序列

# 在指定时间间隔以天为频率生成时间序列
print(pd.date_range('2019-01-01','2019-01-10',freq='D'))
'''
DatetimeIndex(['2019-01-01', '2019-01-02', '2019-01-03', '2019-01-04',
               '2019-01-05', '2019-01-06', '2019-01-07', '2019-01-08',
               '2019-01-09', '2019-01-10'],
              dtype='datetime64[ns]', freq='D')
'''

# 从5.1日12点开始以10秒为频率生成长度为5的序列
print(pd.date_range('2019-5-1 12:00:00',freq='10S',periods=5))
'''
DatetimeIndex(['2019-05-01 12:00:00', '2019-05-01 12:00:10',
               '2019-05-01 12:00:20', '2019-05-01 12:00:30',
               '2019-05-01 12:00:40'],
              dtype='datetime64[ns]', freq='10S')
'''

对于pandas中时间类型的Series序列,通常可以用.dt属性来获取详细的时间信息

time_list = ['2020-06-01 12:00:00', '2020-06-02 13:00:00', '2020-06-05 15:00:00']
df = pd.DataFrame({'timestamp': time_list, 'num': [1, 2, 3]})
df['timestamp'] = pd.to_datetime(df['timestamp'])
print(df['timestamp'].dt.hour)  # 获取timestamp类Series的时间属性
time_delta = df['timestamp'].diff(1)	# 相邻时间作差
print(time_delta.dt.days)  # 获取timedelta类Series的时间属性
'''
0    12
1    13
2    15
Name: timestamp, dtype: int64
0    NaN
1    1.0
2    3.0
Name: timestamp, dtype: float64
'''

6、其他

通过pandas可以便捷地从其他格式文件进行转换。

# 将DataFrame写入csv文件
df.to_csv('foo.csv')
# 从csv文件读数据
df = pd.read_csv('foo.csv')
# excel文件的读写
df = pd.read_excel('foo.xlsx', 'Sheet1', index_col=None, na_values=['NA'])
df.to_excel('foo.xlsx', sheet_name='Sheet1')

在读取文件时如果原文件中有列标签,可以使用header来指定列名,否则可以令header=None,然后使用names属性来自己指定列标签名。使用index_col属性来指定第几列作为行索引值,这样就可以通过索引值对行进行查找。pandas默认low_memory=True在内部对文件进行分块处理,从而在解析时减少了内存使用。如果数据类型不统一,则需要将low_memory设为False,或者通过属性dtype指定读取文件列的数据类型。
例如有如下表格数据node.csv,使用header=0指定第一行作为列名,也可以自己设置列名并指定数据类型

TRANS_NODE_NAMELONGITUDELATITUDECOUNTRY
NP1_POK83.97560228.20403Nepal
NP1_NEP81.36165628.023097India
LK1_SK279.8722087.075681Sri Lanka
# 使用第一行作为列名
nodes=pd.read_csv('node.csv',header=0)	
# 自定义列名并指定行索引
nodes = pd.read_csv('node.csv', header=None, names=['node', 'longtude', 'latitude', 'country'], index_col='node',
                    dtype={'node': str, 'longitude': np.float16, 'latitude': np.float16, 'country': str})
# 使用指定的行索引查找数据
print(nodes['NP1_POK'])

pandas结合matplot可以便捷地进行数据绘图

ts = pd.Series(np.random.randint(0, 500, len(rng)), index=rng)
# 将数据追加到一个数组统一显示
ts=ts.cumsum()
# 调用matplot绘制图
ts.plot()
  • 1
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值