用熊猫解析漂亮的表格数据

Myk*_*tko 5 python clipboard copy-paste pandas

复制包含不同分隔符、列名中的空格等的表的最佳方法是什么。该函数pd.read_clipboard()无法自行管理此任务。

示例 1:

| Age Category | A | B  | C  | D |
|--------------|---|----|----|---|
| 21-26        | 2 | 2  | 4  | 1 |
| 26-31        | 7 | 11 | 12 | 5 |
| 31-36        | 3 | 5  | 5  | 2 |
| 36-41        | 2 | 4  | 1  | 7 |
| 41-46        | 0 | 1  | 3  | 2 |
| 46-51        | 0 | 0  | 2  | 3 |
Run Code Online (Sandbox Code Playgroud)

预期结果:

 Age Category  A  B   C   D    
 21-26         2  2   4   1 
 26-31         7  11  12  5 
 31-36         3  5   5   2 
 36-41         2  4   1   7 
 41-46         0  1   3   2 
 46-51         0  0   2   3
Run Code Online (Sandbox Code Playgroud)

编辑:

示例 2:

+---+---------+--------+
| id|firstName|lastName|
+---+---------+--------+
|  1|     Mark|   Brown|
|  2|      Tom|Anderson|
|  3|   Joshua|Peterson|
+---+---------+--------+
Run Code Online (Sandbox Code Playgroud)

预期结果:

   id firstName  lastName
0   1      Mark     Brown
1   2       Tom  Anderson
2   3    Joshua  Peterson
Run Code Online (Sandbox Code Playgroud)

我寻找一种可以应用于最常见表类型的通用方法。

jor*_*mit 7

之所以如此复杂,是因为这些类型的 ASCII 表在设计时并没有真正考虑到数据传输。它们的真正功能是以视觉上令人愉悦的方式描绘数据。

这并不意味着不能用它来转移到熊猫!让我们开始.read_clipboard()

df = pd.read_clipboard(sep='|').iloc[1:,1:-1]
Run Code Online (Sandbox Code Playgroud)

我们定义|为分隔符,而不是使用逗号作为(默认)分隔符。

.iloc[1:,1:-1]摆脱了第一行(中-----------)和第一和最后一列:由于尾随的|在开始和结束每行pandas看到一个“空”列在那里。

现在剩下的就是从列名和值中去除空格:

stripped_columns = []
for column_name in df.columns:
    df[column_name] = df[column_name].str.strip()
    stripped_columns.append(column_name.strip())
df.columns = stripped_columns
Run Code Online (Sandbox Code Playgroud)

如果你想Age Category成为你的索引:

df.set_index('Age Category', inplace=True)

我要做的最后一步是确保您的所有列现在实际上都包含数字而不是字符串:

df = df.astype('int')
Run Code Online (Sandbox Code Playgroud)

导致:

<class 'pandas.core.frame.DataFrame'>
Index: 6 entries, 21-26 to 46-51
Data columns (total 4 columns):
A    6 non-null int64
B    6 non-null int64
C    6 non-null int64
D    6 non-null int64
dtypes: int64(4)
memory usage: 400.0+ bytes
Run Code Online (Sandbox Code Playgroud)

我不确定您从剪贴板读取它的原因是什么。更优雅的解决方案可能是将其粘贴到.csv文件中并使用.read_csv()必须提供的更高级的功能。然而,必要的转换将保持不变。


Chr*_*s A 7

这是使用re.suband 的另一个潜在解决方案io.StringIO

from io import StringIO
import re

text1 = """
| Age Category | A | B  | C  | D |
|--------------|---|----|----|---|
| 21-26        | 2 | 2  | 4  | 1 |
| 26-31        | 7 | 11 | 12 | 5 |
| 31-36        | 3 | 5  | 5  | 2 |
| 36-41        | 2 | 4  | 1  | 7 |
| 41-46        | 0 | 1  | 3  | 2 |
| 46-51        | 0 | 0  | 2  | 3 |
"""

text2= """
+---+---------+--------+
| id|firstName|lastName|
+---+---------+--------+
|  1|     Mark|   Brown|
|  2|      Tom|Anderson|
|  3|   Joshua|Peterson|
+---+---------+--------+
"""

df1 = pd.read_csv(StringIO(re.sub(r'[|+]|-{2,}', '  ', text1)), sep='\s{2,}', engine='python')
df2 = pd.read_csv(StringIO(re.sub(r'[|+]|-{2,}', '  ', text2)), sep='\s{2,}', engine='python')
Run Code Online (Sandbox Code Playgroud)

[出去]

df1

  Age Category  A   B   C  D
0        21-26  2   2   4  1
1        26-31  7  11  12  5
2        31-36  3   5   5  2
3        36-41  2   4   1  7
4        41-46  0   1   3  2
5        46-51  0   0   2  3
Run Code Online (Sandbox Code Playgroud)

df2

   id firstName  lastName
0   1      Mark     Brown
1   2       Tom  Anderson
2   3    Joshua  Peterson
Run Code Online (Sandbox Code Playgroud)


cs9*_*s95 4

一种选择是硬着头皮对数据进行预处理。这并不是那么糟糕,pd.read_csv它的参数中只能处理这么多的情况,如果你想详尽地处理你处理的情况,你最终将转向正则表达式。

为了处理漂亮打印表的大多数常见情况,我只需编写一个循环来过滤/替换行中的字符,然后使用相对简单的调用读取输出read_csv

import os 

def load(filename):
    with open(filename) as fin, open('temp.txt', 'w') as fout:
        for line in fin:
            if not line.strip()[:2] in {'|-', '+-'}: # filter step
                fout.write(line.strip().strip('|').replace('|', ',')+'\n')

    df = pd.read_csv('temp.txt', sep=r'\s*,\s*', engine='python')
    os.unlink('temp.txt') # cleanup

    return df
Run Code Online (Sandbox Code Playgroud)

df1 = load('data1.txt')
df2 = load('data2.txt')

df1

  Age Category  A   B   C
0        21-26  2   2   4
1        26-31  7  11  12
2        31-36  3   5   5
3        36-41  2   4   1
4        41-46  0   1   3
5        46-51  0   0   2

df2

   id firstName  lastName
0   1      Mark     Brown
1   2       Tom  Anderson
2   3    Joshua  Peterson
Run Code Online (Sandbox Code Playgroud)