复制包含不同分隔符,列名称中的空格等的表的最佳方法是什么。函数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 |
预期结果:
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
编辑:
示例2:
+---+---------+--------+
| id|firstName|lastName|
+---+---------+--------+
| 1| Mark| Brown|
| 2| Tom|Anderson|
| 3| Joshua|Peterson|
+---+---------+--------+
预期结果:
id firstName lastName
0 1 Mark Brown
1 2 Tom Anderson
2 3 Joshua Peterson
我正在寻找一种可以应用于最常见的表类型的通用方法。
答案 0 :(得分:6)
之所以如此复杂,是因为这些类型的ASCII表或在设计时并未真正考虑到数据传输。它们的真正功能是以令人愉悦的方式描绘数据。
这并不意味着不可能用它来转化成熊猫!让我们从.read_clipboard()
开始:
df = pd.read_clipboard(sep='|').iloc[1:,1:-1]
我们将|
定义为分隔符,而不是使用逗号作为(默认)分隔符。
.iloc[1:,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
作为索引:
Age Category
最后一步,我要确保您的所有列现在实际上都包含数字而不是字符串:
df.set_index('Age Category', inplace=True)
结果:
df = df.astype('int')
我不确定您从剪贴板读取它的原因是什么。更为优雅的解决方案可能是将其粘贴到<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
文件中,并使用.read_csv()
提供的更高级的功能。但是,必要的转换将保持不变。
答案 1 :(得分:5)
这是使用re.sub
和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')
[出]
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
df2
id firstName lastName
0 1 Mark Brown
1 2 Tom Anderson
2 3 Joshua Peterson
答案 2 :(得分: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
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
答案 3 :(得分:3)
对于这种类型的表,您可以简单地使用:
df = pd.read_clipboard(sep='|')
然后需要进行最小程度的清理:
df = df.drop(0)
df = df.drop(['Unnamed: 0','Unnamed: 6'], axis=1)
至于“编写这样的电子表格”问题...我看不出有什么比普通演示文稿更方便的了,但是鉴于上述已清除的df
,这是不好的代码:< / p>
df1 = df.append(pd.DataFrame({i:['-'*len(i)] for i in df.columns})).sort_index() #adding the separator to column titles
df2 = pd.DataFrame({str(i)+'|':['|']*len(df1) for i in range(len(df1.columns))})
df3 = df1.join(df2)
col_order = [j for i in [[df1.columns[x], df2.columns[x]] for x in range(len(df1.columns))] for j in i]
df3.index = ['|']*len(df3.index)
然后:
df3[col_order]
Age Category 0| A 1| B 2| C 3| D 4|
| -------------- | --- | ---- | ---- | --- |
| 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 |
(已编辑)