0. 前言
在程序运行过程中生成的数据除了可以可视化出来外,还有就是将数据存储,以便于更细节的分析。
在容易想到的就是把数据存储为.txt
,但该格式的数据并不方便阅读,.csv
格式的文件却可以被记事本或是excel打开,容易被导入到PC表格及数据库中。.csv
文件的存储则需要pandas的数据结构。
1. Pandas基础知识
1.1 数据结构有哪些
图片来源:《Learning the Pandas Library Python Tools for Data Munging, Analysis, and Visual 》by Matt Harrison Michael Prentiss P12
我觉得这张图是把pandas里的数据结构讲得最清楚的,分别代表了一维、二维和三维的数据结构,我觉得该数据结构与numpy最大的区别就是有index和column,数据的索引不再是简单地表示成第几行第几列,而是有了具体的名字。
1.2 Series
一维数据,一行或一列。
如果用数据结构的话来讲,Series就是一个键值对,不过这个键值对是竖着排列的。就跟菜单一样,左边菜名,右边菜的价格。
图片来源:《Learning the Pandas Library Python Tools for Data Munging, Analysis, and Visual 》by Matt Harrison Michael Prentiss P16。
以下代码实验在Pycharm上的Python Console上运行,分析了Seris的创建方式:
# 可以由list创建一列
list1 = [22, 34, -5]
s = pd.Series(list1)
s
Out[5]:
0 22
1 34
2 -5
dtype: int64
# 可以由list创建一行(用两个括号就是可以横向了 !)
list1 = [[22, 34, -5]]
s = pd.Series(list1)
s
Out[5]:
0 [22, 34, -5]
dtype: object
# 可以指定index
s = pd.Series([22, 33, 44], index=['a', 'b', 'c'])
s
Out[7]:
a 22
b 33
c 44
dtype: int64
# 可以由array创建
arr = np.array([2, 3, 4])
s = pd.Series(arr)
s
Out[13]:
0 2
1 3
2 4
dtype: int32
1.3 DataFrames
图片来源:《Learning the Pandas Library Python Tools for Data Munging, Analysis, and Visual 》by Matt Harrison Michael Prentiss P93。
从结构中可以看出是一个二维的数组,其数据帧则理解为一系列的字典,然而其键是列名。
其创建方式,该书的作者也总结了以下:
来源《Learning the Pandas Library Python Tools for Data Munging, Analysis, and Visual 》by Matt Harrison Michael Prentiss P94。
接下来用Python Console分别来尝试一下这几种创建,可以发现用字典创建是列向的,列表创建既可以是横向也可以是列向,取决于列表括号的个数,两个括号就可以创建横向的结构。
# 用字典创建,并修改index
data = {'color' : ['blue','green','yellow','red','white'],
'object' : ['ball','pen','pencil','paper','mug'],
'price' : [1.2,1.0,0.6,0.9,1.7]}
frame = pd.DataFrame(data)
frame
Out[16]:
color object price
0 blue ball 1.2
1 green pen 1.0
2 yellow pencil 0.6
3 red paper 0.9
4 white mug 1.7
frame2 = pd.DataFrame(data, index=['one','two','three','four','five'])
frame2
Out[18]:
color object price
one blue ball 1.2
two green pen 1.0
three yellow pencil 0.6
four red paper 0.9
five white mug 1.7
# 用列表创建
l = [[1, 2], [2, 2]]
frame4 = pd.DataFrame(l)
frame4
Out[25]:
0 1
0 1 2
1 2 2
# 用数组创建
frame3 = pd.DataFrame(np.arange(16).reshape((4,4)),
... index=['red','blue','yellow','white'],
... columns=['ball','pen','pencil','paper'])
frame3
Out[20]:
ball pen pencil paper
red 0 1 2 3
blue 4 5 6 7
yellow 8 9 10 11
white 12 13 14 15
1.4 总结与补充
在numpy的数据结构操作中,还会有与数据库类似的操作,比如索引,加减行列等,甚至有排序、选择、绘图等,目前的疑问是该数据怎么做到数据庞大的。
参考书籍有:
- Learning the Pandas Library Python Tools for Data Munging, Analysis, and Visual by Matt Harrison Michael Prentiss
- Python Data Analytics With Pandas, NumPy, and Matplotlib by Fabio Nelli
- Python可以这样学_董付国_清华大学_2017.2 (1)
2. 数据存储实践
2.1 分析
首先对数据存储步骤进行大致的分析。
首先是数据在程序中的表现形式:
- list
- array
- Seris/Dataframes
其次是数据写到文件中的函数:
- 文件形式(数据需要是
str
形式)def open(file, mode='r', buffering=None, encoding=None, errors=None, newline=None, closefd=True) def write(self, s: AnyStr) -> int def close(self) -> None
- numpy的文件写入函数(数据为
数组
or矩阵
形式)import numpy as np def savetxt(fname, X, fmt='%.18e', delimiter=' ', newline='\n', header='', footer='', comments='# ', encoding=None)
- pandas的文件写入函数(数据为
Seris
等形式)import pandas as pd def to_csv( self, path_or_buf: FilePathOrBuffer[AnyStr] | None = None, sep: str = ",", na_rep: str = "", float_format: str | None = None, columns: Sequence[Hashable] | None = None, header: bool_t | list[str] = True, index: bool_t = True, index_label: IndexLabel | None = None, mode: str = "w", encoding: str | None = None, compression: CompressionOptions = "infer", quoting: int | None = None, quotechar: str = '"', line_terminator: str | None = None, chunksize: int | None = None, date_format: str | None = None, doublequote: bool_t = True, escapechar: str | None = None, decimal: str = ".", errors: str = "strict", storage_options: StorageOptions = None, ) -> str | None
2.2 实践情形描述
每一个循环会生成一组数据(数据非字符串,以list形式存储),每次生成的数据长度不等。
预期是每一轮循环结束后,一组数据能按行存储在指定的文件中。
2.2 代码实现
实现方式一
import numpy as np
path = r"E:\Code\feature_extraction_svm\save_csv.csv"
file = open(path, 'w').close() # 清空文件里的内容
# 第一次循环生成的数据
list1 = [2, 2.2, 2]
arr_tmp = np.zeros((1, len(list1)))
arr_tmp[0:] = list1
with open(path, "a+") as f:
np.savetxt(f, arr_tmp, delimiter=',', fmt='%.10f') # 一定要写上分割符号
# 第二次循环生成的数据
list2 = [1, 1]
arr_tmp = np.zeros((1, len(list2)))
arr_tmp[0:] = list2
with open(path, "a+") as f:
np.savetxt(f, arr_tmp, delimiter=',', fmt='%.10f') # 一定要写上分割符号
结果:
实现方式二
import pandas as pd
list1 = [2, 2, 2]
list2 = [1]
list_all = []
list_all.append(list1)
list_all.append(list2)
print(list_all)
path = r"E:\Code\feature_extraction_svm\save_csv.csv"
data = pd.DataFrame(list_all)
data.to_csv(path, header=0, index=False) # header=0, index=False不显示行列名
效果也是可以的。
不过问题就是appand函数,类似浅拷贝,如果原函数改变,数值就会改变,这不是我想要的,如将list2修改,list_all也会相应变化:
list1 = [2, 2, 2]
list2 = [1]
list_all = []
list_all.append(list1)
list_all.append(list2)
print(list_all)
"""
[[2, 2, 2], [1]]
"""
list2.clear()
print(list_all)
"""
[[2, 2, 2], []]
"""
- 方法一为什么不用open(path, “a”)?
该方式是存储字符串。 为什么列表要转成1行n列的数组
如将上文代码存储代码改写成np.savetxt(f, list1, delimiter=',', fmt='%.10f')
形式,delimiter=','
不起作用,数据会存储为列的形式,哪怕将list以这种方式arr_tmp = np.asarray(list1)
直接转换为数组也是以列的形式存储。为什么不用data.to_csv(path, header=0, index=False)?
问题与2类似,如果是“0维”形式的数据都是按列进行存储。储存的方式都是列向的,即使用了mode='a+
,也只会在列方向上添加,因此只有将所有的数据获取齐了,才有可能呈现横向的这种效果。- 方法一为什么要加with,with的意义和作用?
python学习——numpy savetxt 追加模式