J'ai un Pandas Dataframe généré à partir d'une base de données, qui contient des données avec des codages mixtes. Par exemple:
+----+-------------------------+----------+------------+------------------------------------------------+--------------------------------------------------------+--------------+-----------------------+
| ID | path | language | date | longest_sentence | shortest_sentence | number_words | readability_consensus |
+----+-------------------------+----------+------------+------------------------------------------------+--------------------------------------------------------+--------------+-----------------------+
| 0 | data/Eng/Sagitarius.txt | Eng | 2015-09-17 | With administrative experience in the prepa... | I am able to relocate internationally on short not... | 306 | 11th and 12th grade |
+----+-------------------------+----------+------------+------------------------------------------------+--------------------------------------------------------+--------------+-----------------------+
| 31 | data/Nor/Høylandet.txt | Nor | 2015-07-22 | Høgskolen i Østfold er et eksempel... | Som skuespiller har jeg både... | 253 | 15th and 16th grade |
+----+-------------------------+----------+------------+------------------------------------------------+--------------------------------------------------------+--------------+-----------------------+
Comme on le voit, il y a un mélange d'anglais et de norvégien (codé comme ISO-8859-1 dans la base de données, je pense). Je dois obtenir le contenu de cette sortie Dataframe sous forme de table Markdown, mais sans problèmes d'encodage. J'ai suivi cette réponse (à partir de la question Générer des tables de Markdown? ) et ai obtenu ce qui suit:
import sys, sqlite3
db = sqlite3.connect("Applications.db")
df = pd.read_sql_query("SELECT path, language, date, longest_sentence, shortest_sentence, number_words, readability_consensus FROM applications ORDER BY date(date) DESC", db)
db.close()
rows = []
for index, row in df.iterrows():
items = (row['date'],
row['path'],
row['language'],
row['shortest_sentence'],
row['longest_sentence'],
row['number_words'],
row['readability_consensus'])
rows.append(items)
headings = ['Date',
'Path',
'Language',
'Shortest Sentence',
'Longest Sentence since',
'Words',
'Grade level']
fields = [0, 1, 2, 3, 4, 5, 6]
align = [('^', '<'), ('^', '^'), ('^', '<'), ('^', '^'), ('^', '>'),
('^','^'), ('^','^')]
table(sys.stdout, rows, fields, headings, align)
Cependant, cela génère une erreur UnicodeEncodeError: 'ascii' codec can't encode character u'\xe5' in position 72: ordinal not in range(128)
. Comment puis-je sortir le Dataframe sous forme de table Markdown? C'est-à-dire, dans le but de stocker ce code dans un fichier pour l'utiliser dans l'écriture d'un document Markdown. J'ai besoin que la sortie ressemble à ceci:
| ID | path | language | date | longest_sentence | shortest_sentence | number_words | readability_consensus |
|----|-------------------------|----------|------------|------------------------------------------------|--------------------------------------------------------|--------------|-----------------------|
| 0 | data/Eng/Sagitarius.txt | Eng | 2015-09-17 | With administrative experience in the prepa... | I am able to relocate internationally on short not... | 306 | 11th and 12th grade |
| 31 | data/Nor/Høylandet.txt | Nor | 2015-07-22 | Høgskolen i Østfold er et eksempel... | Som skuespiller har jeg både... | 253 | 15th and 16th grade |
C'est vrai, j'ai donc pris une feuille d'une question suggérée par Rohit ( Python - Chaîne d'encodage - Lettres suédoises ), étendu sa réponse , et voici ce qui suit:
# Enforce UTF-8 encoding
import sys
stdin, stdout = sys.stdin, sys.stdout
reload(sys)
sys.stdin, sys.stdout = stdin, stdout
sys.setdefaultencoding('UTF-8')
# SQLite3 database
import sqlite3
# Pandas: Data structures and data analysis tools
import pandas as pd
# Read database, attach as Pandas dataframe
db = sqlite3.connect("Applications.db")
df = pd.read_sql_query("SELECT path, language, date, shortest_sentence, longest_sentence, number_words, readability_consensus FROM applications ORDER BY date(date) DESC", db)
db.close()
df.columns = ['Path', 'Language', 'Date', 'Shortest Sentence', 'Longest Sentence', 'Words', 'Readability Consensus']
# Parse Dataframe and apply Markdown, then save as 'table.md'
cols = df.columns
df2 = pd.DataFrame([['---','---','---','---','---','---','---']], columns=cols)
df3 = pd.concat([df2, df])
df3.to_csv("table.md", sep="|", index=False)
Un précurseur important à cela est que les colonnes shortest_sentence
et longest_sentence
ne contiennent pas de sauts de ligne inutiles, ce qui a été supprimé en leur appliquant .replace('\n', ' ').replace('\r', '')
avant de les soumettre à la base de données SQLite. Il semble que la solution ne consiste pas à appliquer le codage spécifique à la langue (ISO-8859-1
pour le norvégien), mais plutôt à utiliser UTF-8
à la place de la valeur par défaut ASCII
.
Je l'ai passé dans mon cahier IPython (Python 2.7.10) et j'ai obtenu un tableau comme celui-ci (espacement fixe pour l'apparence ici):
| Path | Language | Date | Shortest Sentence | Longest Sentence | Words | Readability Consensus |
|-------------------------|----------|------------|----------------------------------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-------|-----------------------|
| data/Eng/Something1.txt | Eng | 2015-09-17 | I am able to relocate to London on short notice. | With my administrative experience in the preparation of the structure and content of seminars in various courses, and critiquing academic papers on various levels, I am confident that I can execute the work required as an editorial assistant. | 306 | 11th and 12th grade |
| data/Nor/NoeNorrønt.txt | Nor | 2015-09-17 | Jeg har grundig kjennskap til Microsoft Office og Adobe. | I løpet av studiene har jeg vært salgsmedarbeider for et større konsern, hvor jeg solgte forsikring til studentene og de faglige ansatte ved universitetet i Trønderlag, samt renholdsarbeider i et annet, hvor jeg i en periode var avdelingsansvarlig. | 205 | 18th and 19th grade |
| data/Nor/Ørret.txt.txt | Nor | 2015-09-17 | Jeg håper på positiv tilbakemelding, og møter naturligvis til intervju hvis det er ønskelig. | I løpet av studiene har jeg vært salgsmedarbeider for et større konsern, hvor jeg solgte forsikring til studentene og de faglige ansatte ved universitetet i Trønderlag, samt renholdsarbeider i et annet, hvor jeg i en periode var avdelingsansvarlig. | 160 | 18th and 19th grade |
Ainsi, une table Markdown sans problèmes d’encodage.
Améliorer encore la réponse, pour une utilisation dans IPython Notebook:
def pandas_df_to_markdown_table(df):
from IPython.display import Markdown, display
fmt = ['---' for i in range(len(df.columns))]
df_fmt = pd.DataFrame([fmt], columns=df.columns)
df_formatted = pd.concat([df_fmt, df])
display(Markdown(df_formatted.to_csv(sep="|", index=False)))
pandas_df_to_markdown_table(infodf)
Ou utilisez tabulate :
pip install tabulate
Des exemples d'utilisation sont dans la documentation.
Je recommande la bibliothèque python-tabulate pour générer des tables ascii. La bibliothèque prend également en charge pandas.DataFrame. La bibliothèque n'avait pas de sortie démarquée jusqu'à présent. J'ai fait une requête pull introduisant ce format - il sera peut-être bientôt ajouté au maître (et éventuellement à pypi).
Voici comment l'utiliser:
from pandas import DataFrame
from tabulate import tabulate
df = DataFrame({
"weekday": ["monday", "thursday", "wednesday"],
"temperature": [20, 30, 25],
"precipitation": [100, 200, 150],
}).set_index("weekday")
print(tabulate(df, tablefmt="markdown", headers="keys"))
Sortie:
| weekday | precipitation | temperature |
|-----------|-----------------|---------------|
| monday | 100 | 20 |
| thursday | 200 | 30 |
| wednesday | 150 | 25 |
Essayez ceci. Je l'ai eu pour travailler.
Voir la capture d'écran de mon fichier de démarquage converti en HTML à la fin de cette réponse.
import pandas as pd
# You don't need these two lines
# as you already have your DataFrame in memory
df = pd.read_csv("nor.txt", sep="|")
df.drop(df.columns[-1], axis=1)
# Get column names
cols = df.columns
# Create a new DataFrame with just the markdown
# strings
df2 = pd.DataFrame([['---',]*len(cols)], columns=cols)
#Create a new concatenated DataFrame
df3 = pd.concat([df2, df])
#Save as markdown
df3.to_csv("nor.md", sep="|", index=False)
J'ai essayé plusieurs des solutions ci-dessus dans ce post et j'ai constaté que cela fonctionnait le plus régulièrement.
Pour convertir une trame de données de pandas en une table de démarques, je suggère d'utiliser pytablewriter .
import pandas as pd
import pytablewriter
from StringIO import StringIO
c = StringIO("""ID, path,language, date,longest_sentence, shortest_sentence, number_words , readability_consensus
0, data/Eng/Sagitarius.txt , Eng, 2015-09-17 , With administrative experience in the prepa... , I am able to relocate internationally on short not..., 306, 11th and 12th grade
31 , data/Nor/Høylandet.txt , Nor, 2015-07-22 , Høgskolen i Østfold er et eksempel..., Som skuespiller har jeg både..., 253, 15th and 16th grade
""")
df = pd.read_csv(c,sep=',',index_col=['ID'])
writer = pytablewriter.MarkdownTableWriter()
writer.table_name = "example_table"
writer.header_list = list(df.columns.values)
writer.value_matrix = df.values.tolist()
writer.write_table()
Cela se traduit par:
# example_table
ID | path |language| date | longest_sentence | shortest_sentence | number_words | readability_consensus
--:|--------------------------|--------|------------|------------------------------------------------|------------------------------------------------------|-------------:|-----------------------
0| data/Eng/Sagitarius.txt | Eng | 2015-09-17 | With administrative experience in the prepa... | I am able to relocate internationally on short not...| 306| 11th and 12th grade
31| data/Nor/Høylandet.txt | Nor | 2015-07-22 | Høgskolen i Østfold er et eksempel... | Som skuespiller har jeg både... | 253| 15th and 16th grade
Voici une capture d'écran rendue markdown.
J'ai créé la fonction suivante pour exporter un pandas.DataFrame vers markdown en Python:
def df_to_markdown(df, float_format='%.2g'):
"""
Export a pandas.DataFrame to markdown-formatted text.
DataFrame should not contain any `|` characters.
"""
from os import linesep
return linesep.join([
'|'.join(df.columns),
'|'.join(4 * '-' for i in df.columns),
df.to_csv(sep='|', index=False, header=False, float_format=float_format)
]).replace('|', ' | ')
Cette fonction peut ne pas résoudre automatiquement les problèmes d'encodage de l'OP, mais il s'agit d'un problème différent de celui de la conversion de pandas en markdown.
Voici un exemple de fonction utilisant pytablewriter
et des expressions régulières pour rendre la table de démarcation plus semblable à l'apparence d'une structure de données sur Jupyter (avec les en-têtes de lignes en gras).
import io
import re
import pandas as pd
import pytablewriter
def df_to_markdown(df):
"""
Converts Pandas DataFrame to markdown table,
making the index bold (as in Jupyter) unless it's a
pd.RangeIndex, in which case the index is completely dropped.
Returns a string containing markdown table.
"""
isRangeIndex = isinstance(df.index, pd.RangeIndex)
if not isRangeIndex:
df = df.reset_index()
writer = pytablewriter.MarkdownTableWriter()
writer.stream = io.StringIO()
writer.header_list = df.columns
writer.value_matrix = df.values
writer.write_table()
writer.stream.seek(0)
table = writer.stream.readlines()
if isRangeIndex:
return ''.join(table)
else:
# Make the indexes bold
new_table = table[:2]
for line in table[2:]:
new_table.append(re.sub('^(.*?)\|', r'**\1**|', line))
return ''.join(new_table)
En utilisant l'outil externe pandoc
et pipe:
def to_markdown(df):
from subprocess import Popen, PIPE
s = df.to_latex()
p = Popen('pandoc -f latex -t markdown',
stdin=PIPE, stdout=PIPE, Shell=True)
stdoutdata, _ = p.communicate(input=s.encode("utf-8"))
return stdoutdata.decode("utf-8")
Pour ceux qui cherchent comment faire cela en utilisant tabulate
, j'ai pensé mettre ceci ici pour vous faire gagner du temps:
print(tabulate(df, tablefmt="pipe", headers="keys", showindex=False))
Encore une autre solution. Cette fois, via un wrapper mince autour de tabulate: tabulatehelper
import numpy as np
import pandas as pd
import tabulatehelper as th
df = pd.DataFrame(np.random.random(16).reshape(4, 4), columns=('a', 'b', 'c', 'd'))
print(th.md_table(df, formats={-1: 'c'}))
Sortie:
| a | b | c | d |
|---------:|---------:|---------:|:--------:|
| 0.413284 | 0.932373 | 0.277797 | 0.646333 |
| 0.552731 | 0.381826 | 0.141727 | 0.2483 |
| 0.779889 | 0.012458 | 0.308352 | 0.650859 |
| 0.301109 | 0.982111 | 0.994024 | 0.43551 |
sqlite3 renvoie Unicodes par défaut pour les champs TEXT. Tout était configuré pour fonctionner avant que vous n'ayez introduit la fonction table()
à partir d'une source externe (que vous n'avez pas fournie dans votre question).
La fonction table()
a des appels str()
qui ne fournissent pas de codage, ainsi ASCII est utilisé pour vous protéger.
Vous devez réécrire table()
pour ne pas le faire, surtout si vous avez des objets Unicode. Vous pouvez avoir du succès en remplaçant simplement str()
par unicode()