Ort der Python-Executable
Mit dem folgenden Schnipsel kann man den Pfad der Python.exe bestimmen, die das aktuelle Programm ausführt
import sys print(sys.executable) |
Textsatz mit \LaTeX, Programmieren, Zahlen, etc.
Archive for the ‘Python / SciPy / pandas’ Category.
Mit dem folgenden Schnipsel kann man den Pfad der Python.exe bestimmen, die das aktuelle Programm ausführt
import sys print(sys.executable) |
Hier ein kurzes Beispiel, wie man mit matplotlib Funktionen plotten kann.
import matplotlib.pyplot as plt import numpy as np ax = plt.gca() plt.gca().set_aspect('equal') ax.set_xticks(range(-6,6,1)) ax.set_yticks(range(-6,6,1)) ax.set_xlim([-5, 5]) ax.set_ylim([-5, 5]) ax.spines['top'].set_color('none') ax.spines['bottom'].set_position('zero') ax.spines['left'].set_position('zero') ax.spines['right'].set_color('none') x = np.linspace(-5,5,100) y = 2*x+1 y2 = -0.5*x-2 plt.plot(x, y, 'r', label='2*x+1') plt.plot(x, y2, 'g', label='-0.5*x-2') plt.title('Linear Plots') plt.legend(loc='upper left') plt.grid() plt.show() |
Angenommen, wir haben eine Excel-Datei Daten.xlsx
mit Werten, die in ein entsprechendes XML-Dokument überführt werden müssen.
Mit Python und der Jinja2 Template-Engine ist das flink gemacht. Zuerst definieren wir das Template template.xml
:
<?xml version='1.0' encoding='UTF-8'?> <table name="Tablename"> {% for _,row in data.iterrows() %} <ROW> <COLUMN1>{{row['column1']}}</COLUMN1> <COLUMN2>{{row['column2']}}</COLUMN2> <COLUMN3>{{row['column3']}}</COLUMN3> </ROW> {% endfor %} </table> |
Dann definieren wir den Python-Code:
import pandas as pd # data wrangling import jinja2 # template engine import os # for file-related stuff # create jinja env that can load template from filesystem jinja_env = jinja2.Environment(loader = jinja2.FileSystemLoader(os.path.abspath('.'))) df = pd.read_excel('Daten.xlsx') template = jinja_env.get_template('template.xml') with open('FertigesXML.xml','w') as output: output.write(template.render(data=df)) |
Lassen wir den Python-Code laufen, so erhalten wir das folgende XML:
A while ago (https://www.uweziegenhagen.de/?p=2373) I had an article on how to read the ECB fx rates file with Python. Some time has passed, there are other options in Python 3.
Option 1: Make the Python 2 code run with Python 3
import xml.etree.ElementTree as ET import urllib.request root = ET.parse(urllib.request.urlopen('http://www.ecb.europa.eu/stats/eurofxref/eurofxref-daily.xml')).getroot() for child in root[2][0]: curr = child.get('currency') rate = child.get('rate') print(curr, rate) |
Option 2: Use pandas >=1.3
Starting with version 1.3 pandas offers the read_xml
command, so upgrade using
pip3 install --upgrade pandas
or conda update pandas
.
from urllib.request import urlopen import pandas as pd df = pd.read_xml(urlopen('http://www.ecb.europa.eu/stats/eurofxref/eurofxref-daily.xml'),xpath='//*[@currency]') print(df) |
Hier ein bisschen Python-Code, um zwei CSV Dateien miteinander zu vergleichen. Die Ergebnisse des spalten- und zeilenweisen Vergleichs werden dann zusammengefasst dargestellt, um schnell einen Überblick zu bekommen, wo eine tiefergehende Analyse notwendig ist.
import sys import collections import pandas as pd from tabulate import tabulate file1 = pd.read_csv('file1.csv', sep=';', encoding='UTF-8') file2 = pd.read_csv('file2.csv', sep=';', encoding='UTF-8') columnnames1 = list(file1) columnnames2 = list(file2) if collections.Counter(columnnames1) == collections.Counter(columnnames2): print ("Number of columns and Names match, Comparison possible...\n\n") else: print ("Number of columns and Names are not matching!!! Please check the input!") sys.exit('Error!') # add suffixes to distinguish between actual and expected in the merger file1 = file1.add_suffix('_e') # expected file2 = file2.add_suffix('_t') # t # merge them using the given key, use outer join comparison = pd.merge(file1,file2, how='outer', left_on=['Key_e'], right_on=['Key_t']) # create the columnwise comparison for col in columnnames1: comparison[(col + '_c')] = comparison[(col + '_t')] == comparison[(col + '_e')] # reorder the columns comparison=comparison.reindex(sorted(comparison.columns),axis=1) print(tabulate(comparison, tablefmt="pipe", headers="keys")) # save the result as Excel file comparison.to_excel('result.xlsx') # names of the comparison column check_colnames= [s + '_c' for s in columnnames1] # initialize an empty dataframe for the log logdf=pd.DataFrame(index=[True,False]) for column in check_colnames: t=comparison[column].value_counts() # returns a series tt=pd.DataFrame(t) # makes a DF out of the series logdf = logdf.join(tt,how='outer') # join the two dfs # transpose for better readability logdf = logdf.transpose() # Ensure fixed sequence of the columns logdf=logdf.reindex(sorted(logdf.columns),axis=1) # write to disk logdf.to_excel('logfile.xlsx') # for better viewing on the screen logdf.fillna('-',inplace=True) pd.options.display.float_format = '{:,.0f}'.format print(tabulate(logdf, tablefmt="pipe", headers="keys")) |
Hier ein einfaches Beispiel, wie man mit Python und LaTeX ein PDF mit Kursinformationen erstellen kann.
Zuerst der Python-Teil, der die Apple-Kursdaten seit dem 1.1.2021 in einen Dataframe lädt und dann in eine LaTeX-Tabelle schreibt:
import pandas import pandas_datareader.data as web YAHOO_TODAY="http://download.finance.yahoo.com/d/quotes.csv?s=%s&f=sd1ohgl1vl1" history = web.DataReader('AAPL', "yahoo", start="2021-1-1") history.to_latex('aapl.tex') |
Dann noch der LaTeX-Teil, der a) den Python-Code aus dem LaTeX-Lauf heraus ausführt und b) die erzeugte Tabellen-Datei nur dann einbindet, wenn sie wirklich auch erzeugt wurde.
\documentclass[12pt,ngerman]{scrartcl} \usepackage[a4paper, top=1cm,bottom=1cm,left=1cm, right=1cm]{geometry} \usepackage[T1]{fontenc} \usepackage{booktabs} \makeatletter \newcommand{\testfileexists}[1]{% \IfFileExists{#1}% {\def\inputtestedfile{\@@input #1 }} {\let\inputtestedfile\@empty}% } \makeatother \begin{document} \write18{python runpy.py} \testfileexists{aapl} \inputtestedfile \end{document} |
Mit Seaborn lassen sich auch Stripplots erstellen, hier ein Beispiel. Die Besonderheit ist hier, dass die pd.melt() Funktion genutzt wird, um aus den verschiedenen Variablen des Datensatzes drei Variablen zu machen: eine für den Typ echt/unecht, eine für den Variablennamen und eine für den Wert der jeweiligen Variablen.
#!/usr/bin/env python # coding: utf-8 import seaborn as sns import pandas as pd import requests from bs4 import BeautifulSoup from io import StringIO import matplotlib.pylab as plt headers = { 'Access-Control-Allow-Origin': '*', 'Access-Control-Allow-Methods': 'GET', 'Access-Control-Allow-Headers': 'Content-Type', 'Access-Control-Max-Age': '3600', 'User-Agent': 'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:52.0) Gecko/20100101 Firefox/52.0' } url = "http://www.statistics4u.com/fundstat_eng/data_fluriedw.html" req = requests.get(url, headers) soup = BeautifulSoup(req.content, 'html.parser') data=soup.find('pre').contents[0] str_object = StringIO(data) df = pd.read_csv(str_object,engine='python',skiprows=5,delim_whitespace=True) # Banknotes BN1 to BN100 are genuine, all others are counterfeit df['Type'] = 'Counterfeit' df.loc[df.index[:100], 'Type'] = 'Genuine' print(df) sns.set(style="whitegrid", palette="muted") #df = df[['Left', 'Diagonal', 'Type']] df = pd.melt(df, "Type", var_name="Variable") sp = sns.stripplot(x="value", y="Variable", hue="Type", data=df, dodge=True, alpha=.75, zorder=1) #sp.set(xlim=(127, 143)) sp.legend_.remove() plt.show() |
Das Bild, was dabei erzeugt wird, ist aber eher schlecht. Da die Variablen teilweise sehr unterschiedliche Skalen haben, erkennt man eigentlich nur Punktwolken, die übereinander liegen.
Die Lösung besteht darin, nur die Variablen gemeinsam zu plotten, die sehr nah beieinander liegende Skalen haben. Dazu entfernt man die beiden Hashes aus den auskommentierten Python-Zeilen, um nur noch die Variablen Left und Diagonal zu plotten und um die Skale anzupassen.
Dann erkennt man im Bild, dass die Diagonale echte und falsche Banknoten schön voneinander trennt.
Im Beitrag „CSV-Dateien mit speziellen Spaltentrennern in Python laden“ hatte ich gezeigt, wie man mit BS4 Dateien aus Webseiten extrahieren und abspeichern kann, um sie dann in pandas weiterzuverarbeiten. Es geht auch ohne den Umweg der CSV-Datei, wenn man die StringIO Klasse aus dem io Modul nutzt.
Wir laden das Modul und instanziieren dann ein Objekt der Klasse mit dem von BS4 gefundenen Datensatz. Diese Objekt wird dann anstelle des Pfades der CSV-Datei an die pd.read_csv()
Funktion übergeben.
import pandas as pd import requests from bs4 import BeautifulSoup from io import StringIO headers = { 'Access-Control-Allow-Origin': '*', 'Access-Control-Allow-Methods': 'GET', 'Access-Control-Allow-Headers': 'Content-Type', 'Access-Control-Max-Age': '3600', 'User-Agent': 'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:52.0) Gecko/20100101 Firefox/52.0' } url = "http://www.statistics4u.com/fundstat_eng/data_fluriedw.html" req = requests.get(url, headers) soup = BeautifulSoup(req.content, 'html.parser') data=soup.find('pre').contents[0] str_object = StringIO(data) df = pd.read_csv(str_object,engine='python',skiprows=5,delim_whitespace=True) print(df) |
Hier ein Beispiel, wie man Bilder für eine Animation mit matplotlib erstellen kann, adaptiert von im Netz gefundenen Code
Der folgende Python-Code erzeugt 720 einzelne Bilder und legt diese im Dateisystem ab. Mittels magick -quality 100 *.png outputfile.mpeg
werden dann die Bilder zu einem MPEG-Video kombiniert. Hinweis: Nur unter Windows heißt der Befehl „magick“ da „convert“ auch ein Systemprogramm ist.
import matplotlib.pyplot as plt import pandas as pd import seaborn as sns from mpl_toolkits.mplot3d import Axes3D df = sns.load_dataset('iris') sns.set(style = "darkgrid") fig = plt.figure() fig.set_size_inches(16, 9) ax = fig.add_subplot(111, projection = '3d') x = df['sepal_width'] y = df['sepal_length'] z = df['petal_width'] ax.set_xlabel("sepal_width") ax.set_ylabel("sepal_lesngth") ax.set_zlabel("petal_width") c = {'setosa':'red', 'versicolor':'blue', 'virginica':'green'} ax.scatter(x, y, z,c=df['species'].apply(lambda x: c[x])) for angle in range(0, 720): ax.view_init((angle+1)/10, angle) plt.draw() plt.savefig('r:/'+str(angle).zfill(3)+'.png')
Eine kürzere Version der Animation habe ich unter https://www.youtube.com/watch?v=gdgvXpq4k1w abgelegt.
Hinweise zu anderen Konvertierungsprogrammen gibt es unter anderem hier: https://www.andrewnoske.com/wiki/Convert_an_image_sequence_to_a_movie
Um einige Klassifikations-Algorithmen in Python ausprobieren zu können habe ich heute die Swiss Banknote Data von Flury und Riedwyl benötigt. Die Daten sind im Netz z.B. unter http://www.statistics4u.com/fundstat_eng/data_fluriedw.html verfügbar, ich wollte sie aber nicht manuell einladen müssen.
Mit dem folgenden Code, adaptiert von https://hackersandslackers.com/scraping-urls-with-beautifulsoup/, kann man die Daten lokal abspeichern und dann in einen pandas Dataframe einladen.
import pandas as pd import requests from bs4 import BeautifulSoup headers = { 'Access-Control-Allow-Origin': '*', 'Access-Control-Allow-Methods': 'GET', 'Access-Control-Allow-Headers': 'Content-Type', 'Access-Control-Max-Age': '3600', 'User-Agent': 'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:52.0) Gecko/20100101 Firefox/52.0' } url = "http://www.statistics4u.com/fundstat_eng/data_fluriedw.html" req = requests.get(url, headers) soup = BeautifulSoup(req.content, 'html.parser') a=soup.find('pre').contents[0] with open('banknote.csv','wt') as data: data.write(a) df = pd.read_csv('banknote.csv',engine='python',skiprows=5,delim_whitespace=True) print(df) |