Aus Python heraus Pakete installieren
import pip def install(package): if hasattr(pip, 'main'): pip.main(['install', package]) else: pip._internal.main(['install', package]) # Beispiel für spyder ide if __name__ == '__main__': install('spyder') |
Textsatz mit \LaTeX, Programmieren, Zahlen, etc.
Posts tagged ‘Python’
import pip def install(package): if hasattr(pip, 'main'): pip.main(['install', package]) else: pip._internal.main(['install', package]) # Beispiel für spyder ide if __name__ == '__main__': install('spyder') |
Der folgende Trick hat mir einige Klimmzüge erspart. In einer Textdatei gab es an diversen Stellen mehrfache Leerzeichen, die ich durch ein einzelnes ersetzen wollte.
Ich hätte jetzt einfach so lange doppelte Leerzeichen durch ein einzelnes ersetzen können, bis keine doppelten Leerzeichen mehr vorhanden sind, über einen regular expression geht es aber viel eleganter.
import re s = 'a b c' print(re.sub('\s+',' ',s)) |
Ich hatte vor kurzem das Problem (oder die „Challenge“), einen sehr komplexen Cognos-Report anpassen zu müssen. In mehreren dutzend Formeln mussten Formeln angepasst werden, den Formel-Check zur Prüfung meiner Anpassungen konnte ich jedoch nicht nutzen, da die Datenüberprüfung unendlich lang gedauert hätte (schlechtes Report-Design…).
Mit Python gab es aber eine einfache und elegante Lösung, die mit dem Export des Report-Designs in eine XML-Datei begann.
In der XML-Datei fanden sich dann Schnipsel wie
<expression>abs(total((if ([Database].[storedProc].[ColumnID]=6) then ([Database].[storedProc].[Amount]) else (0))))</expression>
Mit dem folgenden Programm-Code konnte ich dann innerhalb der expression-Tags einfach die öffnenden und schließenden Klammern zählen. Wenn die Zahl der öffnenden Klammern nicht der Zahl der schließenden Klammern entsprach, war die Formel noch falsch.
import re buffer = open('./Report.xml','r').read() results = re.findall(r"(<expression>)(.*)(</expression>)",buffer,re.MULTILINE) for result in results: expression = result[1] opened = expression.count('(') closed = expression.count(')') if opened != closed: print(expression) |
Nehmen wir mal an, wir haben eine Excel-Datei Daten.xlsx
mit Namen, in der es Fehleingaben durch beispielsweise einen Buchstabendreher geben kann:
Mit Python und dem Levenshtein-Paket können wir die Ähnlichkeit der Namen recht einfach prüfen.
import pandas as pd import Levenshtein df = pd.read_excel('Daten.xlsx') df = df.sort_values(by=['Name']) df = df.reset_index(drop=True) dfs= df.shift() # Shift df by one row dfs = dfs.rename(columns={'Name': 'Nameshifted'}) df_combined = pd.concat([df,dfs],axis=1) # combine original and shifted df df_combined = df_combined.fillna('') # remove NaNs for index, row in df_combined.iterrows(): df_combined.loc[index,'Ratio'] = (Levenshtein.ratio(row['Name'], row['Nameshifted'])) df_combined.loc[index,'Distance'] = (Levenshtein.distance(row['Name'], row['Nameshifted'])) print(df_combined) |
Als Ergebnis erhält man dann einen Dataframe, der die sortierten Namen miteinander vergleicht und die Levenshtein-Ratio sowie die Levenshtein-Distanz ausgibt.
Name | Nameshifted | Ratio | Distance | |
---|---|---|---|---|
0 | Ambacher | 0.000000 | 8.0 | |
1 | Bertram | Ambacher | 0.266667 | 8.0 |
2 | Cderick | Bertram | 0.285714 | 6.0 |
3 | Cedrick | Cderick | 0.857143 | 2.0 |
4 | Dorn | Cedrick | 0.181818 | 6.0 |
5 | Elba | Dorn | 0.000000 | 4.0 |
6 | Friedrich | Elba | 0.000000 | 9.0 |
7 | Gastav | Friedrich | 0.000000 | 9.0 |
8 | Gustav | Gastav | 0.833333 | 1.0 |
9 | Horn | Gustav | 0.000000 | 6.0 |
10 | Immenweg | Horn | 0.166667 | 7.0 |
11 | Klaas | Immenweg | 0.000000 | 8.0 |
12 | Klaus | Klaas | 0.800000 | 1.0 |
Bei hoher Ratio oder kleiner Distanz sollte man sich die Werte anschauen.
Hinweis: Ich bin hier davon ausgegangen, dass nur im Namen der nächsten Zeile ein Dreher auftreten kann. Vergleicht man alle n Namen mit allen anderen n-1 Namen, so wird es schnell aufwändig und zeitintensiv.
Hier noch ein weiteres Beispiel, wie man sich mit Python sinnlose manuelle Arbeiten erleichtern kann. Gegeben sei die folgende Verzeichnisstruktur:
Verzeichnis1 Ordner1 Unterordner1 Willich.txt Ordner2 Unterordner2 Willich.txt Ordner3 Unterordner3 Willich.txt
Die in den Ordnern liegenden Dateien sind alle gleich benannt (trotz unterschiedlicher Inhalte), sollen aber für die weitere Verarbeitung in einen Ordner verschoben werden. Man kann sie jetzt manuell nach dem Schema „Ordnerx-Unterordnerx-Dateiname“ umbenennen, man kann es aber auch lassen und ein kurzes Python-Skript dazu schreiben. Spätestens bei 20 oder 30 Dateien lohnt sich der Aufwand der initialen Entwicklung, das Beispiel lässt sich auch leicht auf andere Aufgaben übertragen. Die folgende Python-Datei speichert man in „Verzeichnis1“, dieses Verzeichnis bildet dann den root-Pfad. Der Rest ist dann einfach nur cleveres Auswerten des Pfades und das Wechseln der Backslashes in Unterstriche, um den neuen Pfad zu bauen.
import os for (root,dirs,files) in os.walk('.'): for file in files: fullpath = os.path.join(root,file) if fullpath.endswith('.txt'): newpath = root+'\\'+root[2:].replace('\\','_')+'_'+file print(newpath) os.rename(fullpath, newpath) |
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:
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} |
Update vom 05.05.2024:
Um den DataFrame zu befüllen, funktioniert der obige Code nicht mehr. Hier ist ein Workaround zum Anpassen:
import pandas as pd import yfinance as yf df = pd.DataFrame(yf.download('MSFT', start = '2012-01-01', end='2017-01-01')) |
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