# Pandas Notes

## CSV related

### 读取 CSV

```python
pd.read_csv(filepath_or_buffer, sep, header, parse_dates, index_col, prefix, encoding)
```

参数： **filepath\_or\_buffer**: 字符串，或者任何对象的read()方法。这个字符串可以是URL，有效的URL方案包括http、ftp、s3和文件。可以直接写入"文件名.csv"。\
**sep**: 分隔符，默认为 ','\
**header**: 将行号用作列名，且是数据的开头。默认为0，即将读取的第一行作为每一列的列名。\
注意当 **skip\_blank\_lines=True** 时，这个参数忽略注释行和空行。所以header=0表示第一行是非空的数据而不是文件的第一行。若令 `header=None` 则第一行被当作数据，df的列名为序号 1,2,3...\
**parse\_dates**: 布尔类型值 or int类型值的列表 or 列表的列表 or 字典（默认值为 FALSE）\
1\. True:尝试解析索引\
2\. 由int类型值组成的列表(如\[1,2,3]):作为单独数据列，分别解析原始文件中的1,2,3列\
3\. 由列表组成的列表(如\[\[1,3]]):将1,3列合并，作为一个单列进行解析\
4\. 字典(如{'foo'：\[1, 3]}):解析1,3列作为数据，并命名为foo

**squeeze**: 布尔值，默认FALSE\
TRUE 如果被解析的数据只有一列，那么返回 **Series** 类型。\
**prefix**: 给列名加的前缀\
**encoding**: 导入出现乱码的时候使用，常用的有 'utf-8', 'gbk'

### 写入 CSV

```python
dataframe.to_csv(path_or_buf,sep,na_rep,mode,columns,header,index)
```

参数：\
**path\_or\_buf**: 字符串，放文件名、相对路径、文件流等；\
**sep**: 字符串，分隔符，跟read\_csv()的一个意思\
**na\_rep**: 字符串，将NaN转换为特定值\
**mode**: 默认模式是覆盖写，当 `mode='a'` 为**追加写**\
**columns**: 列表，指定哪些列写进去\
**header**: 默认header=0，如果没有表头，设置header=None\
**index**: 关于索引的，默认True，写入索引

## Dataframe

### list 转化 dataframe

```python
a = [['a', '1.2', '4.2'], ['b', '70', '0.03'], ['x', '5', '0']]  
df = pd.DataFrame(a, columns=['one', 'two', 'three'])
```

### DataFrame 转 Numpy

```python
df=pd.DataFrame(xxx)

# 三种方式
1. df.values # Not Callable
2. df.as_matrix()
3. np.array(df)
```

### Numpy 转 DataFrame

```python
mat = np.random.rand(3, 4)

df = pd.DataFrame(mat, columns=('colA', 'colB', 'colC', xxx)) # 给列命名
```

### 插入一行

貌似没有直接的插入选项，但是可以通过每次新建一个临时的 `pd.DataFrame` 然后 `df.append()` 实现操作：

```python
df = pd.DataFrame(columns=('name', 'sex', 'id'))
name = '小王'
sex = '男'
id = '001'
df = df.append(pd.DataFrame({'name':[name],'sex':[sex],'id':[id]}), ignore_index=True)
```

几点重要的地方：\
1\. DataFrame.append() 不会对自己产生改变，要在前面加上 df= 。\
2\. append() 内部其实就是临时新建了一个实例，这里新建实例的方法是采用字典的方式 `{'attr':[val], xxx }` 对于每个属性后面跟上初始化的赋值 val，注意 val 要用 \[] 括起来。\
3\. 要加上 `ignore_index=True` 否则可能新建的实例会有自带的索引导致多出一列，append之后得不到自己想要的结果。

### 遍历元素

例子:

```python
   c1  c2  
0  10  100  
1  11  110  
2  12  120
```

#### Dataframe.iterrows()

按行遍历，将 DataFrame 的**每一行**迭代为 (index, Series) 对，可以通过 `row[name]` 对元素进行访问。

```python
>>> for index, row in df.iterrows():
...     print(index)
...     print(row['c1'], row['c2'])
...

Output: 
0
(10, 100)
1
(11, 110)
2
(12, 123)
```

#### Dataframe.itertuples()

按行遍历，将 DataFrame 的**每一行**迭代为元组(tuple)，可以通过 `getattr(row, name)` 对元素进行访问，比 iterrows() **效率高**。

```python
>>> for row in df.itertuples():
...     print(getattr(row, 'c1'), getattr(row, 'c2'))
...

Output: 
(10, 100)
(11, 110)
(12, 123)
```

#### Dataframe.iteritems()

按列遍历，将DataFrame的**每一列**迭代为 **(列名, Series)** 对，可以通过 row\[index] 对元素进行访问。

```python
>>> for index, row in df.iteritems():
...     print(index)
...     print(row[0], row[1], row[2])
...

Output:
c1
(10, 11, 12)
c2
(100, 110, 123)
```

### 选取某一列或某一行

```python
data['w']    #选择表格中的'w'列，使用类字典属性，返回的是 Series 类型

data.w       #选择表格中的'w'列，使用点属性，返回的是 Series 类型

data[['w']]  #选择表格中的'w'列，返回的是 DataFrame 类型

data[0:2]  #返回第1行到第2行的所有行，前闭后开，包括前不包括后

data[1:2]  #返回第2行，从0计，返回的是单行，通过有前后值的索引形式，
           #如果采用data[1]则报错，data[1:1]返回为空

data.iloc[-1]   #选取DataFrame最后一行，返回的是 Series
data.iloc[-1:]  #选取DataFrame最后一行，返回的是 DataFrame
```

### 给某列更名

1. 读取文件的时候重命名 names = new\_col，可以在读取文件的时候，给出新列名。  &#x20;

   ```python
   new_col = ['new1', 'new2',... , 'newn']
   pd.read_csv('data', names = new_col, header=0)
   ```
2. 全部重命名 columns = new\_columns，新列名的长度必须与旧列名**一致**. &#x20;

   ```python
   new_col = ['new1', 'new2',... , 'newn']
   dataframe.columns = new_col
   ```
3. 部分重命名 columns = dict，使用**字典类型的数据**对列进行重命名。  &#x20;

   ```python
   dataframe.rename(columns = {"old_name": "new_name"})
   dataframe.rename(columns = {"old1": "new1", "old2":"new2"},  inplace=True)
   ```
4. 因为dataframe的columns就是string类，所以可以直接使用 str.replace &#x20;

   ```python
   dataframe.columns = dataframe.columns.str.replace('' '', ''_'')
   ```

### 拼接操作

#### pandas.concat()

pandas 的顶级方法，提供了axis设置可用于 dataframe 间**行方向**（增加行，下同）或**列方向**（增加列，下同）进行内联或外联拼接操作。

```python
concat(objs, axis=0, join='outer', join_axes=None, ignore_index=False,
           keys=None, levels=None, names=None, verify_integrity=False,
           copy=True)
```

参数说明:\
**objs**: 需要进行拼接的对象的集合，要用 `[]` 框起来 **axis**: 拼接轴方向，默认为0，沿行拼接；若为1，沿列拼接\
**join**: 默认外联'outer'，拼接另一轴所有的label，缺失值用NaN填充；内联'inner'，只拼接另一轴相同的label；\
**join\_axes**: 指定需要拼接的轴的labels，可在join既不内联又不外联的时候使用\
**ignore\_index**: 对index进行重新排序\
**keys**: 多重索引

#### Dataframe.append()

dataframe 数据类型的方法，提供了**行方向**的拼接操作。

```python
append(self, other, ignore_index=False, verify_integrity=False)
```

常用参数说明:\
**other**: 另一个dataframe\
**ignore\_index**: 若为True，则对index进行重排\
**verify\_integrity**: 对index的**唯一性进行验证**，若有重复，报错。若已经设置了ignore\_index，则该参数无效

#### Dataframe.join()

dataframe 数据类型的方法，提供了**列方向**的拼接操作，支持**左联、右联、内联和外联**四种操作类型。

```python
join(other, on=None, how='left', lsuffix='', rsuffix='', sort=False)
```

常用参数说明:\
**on**: 参照的左边df列名key（可能需要先进行set\_index操作），若未指明，按照index进行join\
**how**: {'left', 'right', 'outer', 'inner'}

* 默认'left'，即按照左边df的index(若声明了on，则按照对应的列)； &#x20;
* 若为'right' 则按照右边的df；
* 若'inner'为内联方式；
* 若为'outer'为全连联方式。 &#x20;

**sort**: 是否按照join的key对应的值大小进行排序，默认False\
**lsuffix**，**rsuffix**: 当left和right两个df的列名出现冲突时候，通过设定后缀的方式避免错误

#### Dataframe.merge()

pandas 的顶级方法，提供了类似于 SQL 数据库连接操作的功能，支持**左联、右联、内联和外联**等全部四种SQL连接操作类型。

```python
pd.merge(left, right, how='inner', on=None, left_on=None, right_on=None,
          left_index=False, right_index=False, sort=False,
          suffixes=('_x', '_y'), copy=True, indicator=False,
          validate=None):
```

既可作为pandas的顶级方法使用，也可作为DataFrame数据结构的方法进行调用\
常用参数说明:\
**how**: {'left', 'right', 'outer', 'inner'}

* 默认'inner'，类似于SQL的内联； &#x20;
* 'left' 类似于SQL的左联；  &#x20;
* 'right' 类似于SQL的右联； &#x20;
* 'outer' 类似于SQL的全联。 &#x20;

**on**: 进行合并的参照列名，必须一样。若为None，方法会自动匹配两张表中相同的列名\
**left\_on**: 左边df进行连接的列\
**right\_on**: 右边df进行连接的列\
**suffixes**: 左、右列名称前缀\
**validate**: 默认None

* "one\_to\_one" ，验证是否一对一关系 &#x20;
* "one\_to\_many" ，验证是否一对多关系 &#x20;
* "many\_to\_one"，验证是否多对一关系 &#x20;
* "many\_to\_many"，验证是否多对多关系 &#x20;

SQL语句复习:

```sql
内联: SELECT a.*, b.* from table1 as a inner join table2 as b on a.ID=b.ID
左联: SELECT a.*, b.* from table1 as a left join table2 as b on a.ID=b.ID
右联: SELECT a.*, b.* from table1 as a right join table2 as b on a.ID=b.ID
全联: SELECT a.*, b.* from table1 as a full join table2 as b on a.ID=b.ID
```

### 删除某一行或某一列

```python
dataframe.drop(label=['xxx','xxx','xxx'], axis=0, inplace=False)
```

参数：\
**label**: 是指定要删除的列或行的行号或列名称\
**axis**: 删除的轴，默认为0，沿行方向进行删除，axis=1为沿列方向进行删除\
**inplace**: 这个函数返回的是修改后的dataframe 但并不会改变自身，inplace=True的时候可以同时对自身进行修改

### 求交并差集

对于colums都相同的dataframe做过滤的时候，例如：

```python
df1 = DataFrame([['a', 10, '男'], 
                 ['b', 11, '男'], 
                 ['c', 11, '女'], 
                 ['a', 10, '女'],
                 ['c', 11, '男']], 
                columns=['name', 'age', 'sex'])

df2 = DataFrame([['a', 10, '男'], 
                 ['b', 11, '女']],
                columns=['name', 'age', 'sex'])
```

#### 取交集

```python
print(pd.merge(df1,df2,on=['name', 'age', 'sex']))
```

#### 取并集

```python
print(pd.merge(df1,df2,on=['name', 'age', 'sex'], how='outer'))
```

#### 取差集

差集即从df1中过滤df1在df2中存在的行\
**思路**：将df2两次合并到df1中，然后删除重复项。\
**为什么要合并两次？** 因为合并一次会求出对称差 ((A-B)$\cup$(B-A)) ，两次就能够将对称差中的 df2 也变成重复项从而删除掉。

```python
df1 = df1.append(df2)  # 合并第一次
df1 = df1.append(df2)  # 合并第二次
df1 = df1.drop_duplicates(subset=['name', 'age', 'sex'],keep=False)
print(df1)
```

### pandas 常用函数

#### DataFrame.drop\_duplicates

| Parameters | Effect                                                                                                                                                                                                                                                                                      |
| :--------: | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|   subset   | <p>column label or sequence of labels, optional<br>Only consider certain columns for identifying duplicates, <strong>by default use all of the columns</strong></p>                                                                                                                         |
|    keep    | <p>{<strong>'first', 'last', False</strong>}, default <strong>'first'</strong><br><strong>first</strong> : Drop duplicates except for the first occurrence.<br><strong>last</strong> : Drop duplicates except for the last occurrence.<br><strong>False</strong> : Drop all duplicates.</p> |
| take\_last | *deprecated*                                                                                                                                                                                                                                                                                |
|   inplace  | <p><strong>boolean</strong>, default <strong>False</strong><br>Whether to drop duplicates in place or to return a copy</p>                                                                                                                                                                  |
|    cols    | kwargs only argument of subset \[*deprecated*]                                                                                                                                                                                                                                              |

**Returns**: deduplicated: DataFrame

e.g.

```python
df=pd.DataFrame(xxx)
df.drop_duplicates(subset=['id','name'], keep=False) # 根据id和name双重判断，重复的一个都不留
df.drop_duplicates(subset=['id'], inplace=True) # 根据id判断，只留下第一个找到的重复值，并且赋值给自身
```

#### Series.groupby

|  Parameters | Effect                                                                                                                                                                                                                                                                                                        |
| :---------: | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|     axis    | <p><strong>int</strong>, <strong>default 0</strong> <br> 0 for row <br> 1 for col</p>                                                                                                                                                                                                                         |
|     sort    | <p><strong>boolean</strong>, <strong>default True</strong> <br> Sort group keys. <br> Get better performance by turning this off. <br> Note this does not influence the order of observations within each group. groupby <strong>preserves the order</strong> of rows <strong>within</strong> each group.</p> |
| group\_keys | <p><strong>boolean</strong>, <strong>default True</strong> <br> When calling apply, <strong>add group keys</strong> to index to identify pieces.</p>                                                                                                                                                          |
|   squeeze   | <p><strong>boolean</strong>, <strong>default False</strong> <br> reduce the dimensionality of the return type if possible, otherwise return a consistent type</p>                                                                                                                                             |

**Returns**: GroupBy object

**注意**：这里的 groupby 的调用函数是 Series 不是 DataFrame，而 DataFrame需要通过 df\['col'] 取值得到 Series。\
**注意**：这里返回的是 Series 格式，只包括 **被筛选的列** 和 **key列**

e.g.

```python
# 一条记录有 id name commit_time
# 现在需要找到每个学生的最晚提交时间
# 由于 commit_time 是 date 格式所以可以直接比较大小
# 思路：根据id和name将所有commit_time进行分组然后取组内最大  
res = df['commit_time'].groupby([df['id'], df['name']]).max()  
或 res = df[['name', 'commit_time']].groupby(df['id']).max()
```

## Reference

1. [csdn | pandas按行按列遍历Dataframe的几种方式](https://blog.csdn.net/sinat_29675423/article/details/87972498) &#x20;
2. [csdn | 取dataframe的一列或一行](https://blog.csdn.net/m0_37876745/article/details/88828928) &#x20;
3. [csdn | Pandas中的拼接操作(concat,append,join,merge)](https://blog.csdn.net/guofei_fly/article/details/85455813) &#x20;
4. [简书 | pandas读取文件的read\_csv()](https://www.jianshu.com/p/ebb64a159104) &#x20;
5. [cnblogs | Pandas 通过追加方式合并多个csv](https://www.cnblogs.com/bigtreei/p/9946072.html) &#x20;
6. [cnblogs | pd.read\_csv() 、to\_csv() 之 常用参数](https://www.cnblogs.com/wyy1480/p/10322336.html) &#x20;
7. [cnblogs | 给DataFrame的列命名或重命名](https://www.cnblogs.com/wqbin/p/11590425.html) &#x20;
8. [cnblogs | pandas DataFrame行或列的删除方法](https://www.cnblogs.com/datasnail/p/9767158.html) &#x20;
9. [csdn | pandas: DataFrame 交集并集补集](https://blog.csdn.net/qq_40981268/article/details/85957177) &#x20;
10. [csdn | list 转化 dataframe](https://blog.csdn.net/ls13552912394/article/details/80317905) &#x20;
11. [csdn | Pandas创建一个空DataFrame，并逐行插入数据](https://blog.csdn.net/roamer314/article/details/80886075) &#x20;
12. [pandas 0.17.0 documents](https://pandas.pydata.org/pandas-docs/version/0.17.0/api.html) &#x20;
13. [cnblogs | python中groupby函数详解](https://www.cnblogs.com/Yanjy-OnlyOne/p/11217802.html)  &#x20;
