数组:将稀疏数组合并为一个更密集的数组

时间:2017-02-03 09:48:09

标签: python pandas

我的下表是稀疏填充的,但在列中也有重复。

+------------+---------+
| LX ID      | ISIN    |
+------------+---------+
| A          | X       |
| B          | Y       |
|            | Z       |
| B          |         |
|            | X       |
| A          |         |
| B          | Y       |
| A          | X       |
+------------+---------+

使用df[["LX ID", "ISIN"]].drop_duplicates()会产生以下内容,它会删除相同的行,但仍然在列中有重复项(例如最后3列):

+------------+---------+
| LX ID      | ISIN    |
+------------+---------+
| A          | X       |
| B          | Y       |
|            | Z       |
| B          |         |
|            | X       |
| A          |         |
+------------+---------+

你会提出什么解决方案,它会丢弃已经有一行更完整的行(例如,丢弃最后一行,因为第一行更好地填写)?最终浓缩表的一个例子如下:

+------------+---------+
| LX ID      | ISIN    |
+------------+---------+
| A          | X       |
| B          | Y       |
|            | Z       |
+------------+---------+

谢谢,

基兰

1 个答案:

答案 0 :(得分:0)

以下是使用外部联接的一种方法,有两种风格..输入已经稍微调整,以证明具有两个值的行在具有一个值的行之前是有利的。

首先,设置:

In [1]: import pandas as pd
   ...: 
   ...: ids = pd.DataFrame(
   ...:     index=['LX ID', 'ISIN'],
   ...:     data=[['A', 'B', '', 'B', '', 'A', 'B', 'A'], 
   ...:           ['', 'Y', 'Z', '', 'X', 'X', 'Y', 'X']], 
   ...: ).T
   ...: ids


Out[1]: 
  LX ID ISIN
0     A     
1     B    Y
2          Z
3     B     
4          X
5     A    X
6     B    Y
7     A    X

然后按照“完整性”排序'

In [2]: ids['full'] = (ids['LX ID'] != '') & (ids['ISIN'] != '')
   ...: ids.sort_values('full', ascending=False, inplace=True)
   ...: ids

Out[2]: 
  LX ID ISIN   full
1     B    Y   True
5     A    X   True
6     B    Y   True
7     A    X   True
0     A       False
2          Z  False
3     B       False
4          X  False

然后拆分两个系列,丢弃空白并删除重复项(默认情况下保留第一次出现):

lx = ids['LX ID']
isin = ids['ISIN']
lx = lx[lx != ''].drop_duplicates()
isin = isin[isin != ''].drop_duplicates()

然后在两种方式之一中使用外连接,用空字符串替换NaN ..正确的行连接在一起,因为保留了分隔两个系列时第一个数据框的隐式索引。

明确加入:

In [3]: pd.DataFrame(lx).join(isin, how='outer').fillna('')

Out[3]: 
  LX ID ISIN
1     B    Y
2          Z
5     A    X

或通过构造函数:

In [4]: pd.DataFrame([lx, isin]).T.fillna('')

Out[4]: 
  LX ID ISIN
1     B    Y
2          Z
5     A    X

如果我们有NaN而不是空格(如果从xls / csv读取,那么默认情况下可能是你得到的东西)可以简化整个事情:

In [5]: import pandas as pd
   ...: _ = pd.np.nan
   ...: ids = pd.DataFrame(
   ...:     index=['LX ID', 'ISIN'],
   ...:     data=[['A', _, 'B', _, 'B', _, 'A', 'B', 'A'], 
   ...:           [_, _, 'Y', 'Z', _, 'X', 'X', 'Y', 'X']], 
   ...: ).T
   ...: ids


Out[5]: 
  LX ID ISIN
0     A  NaN
1   NaN  NaN
2     B    Y
3   NaN    Z
4     B  NaN
5   NaN    X
6     A    X
7     B    Y
8     A    X

应用于行的count函数计算非NaN值,然后我们将其用于排序:

In [6]: ids['order'] = ids.count(axis=1)
   ...: ids.sort_values('order', ascending=False, inplace=True)

Out[6]: 
  LX ID ISIN  order
2     B    Y      2
6     A    X      2
7     B    Y      2
8     A    X      2
0     A  NaN      1
3   NaN    Z      1
4     B  NaN      1
5   NaN    X      1
1   NaN  NaN      0

然后类似于之前,但使用dropna()而不是显式空字符串比较:

In [7]: lx = ids['LX ID'].dropna().drop_duplicates()
    ...: isin = ids['ISIN'].dropna().drop_duplicates()
    ...: pd.DataFrame(lx).join(isin, how='outer')

Out[7]: 
  LX ID ISIN
2     B    Y
3   NaN    Z
6     A    X