Dataframes aus verschiedenen Prozessen zusammenfügen

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
LukeNukem
User
Beiträge: 232
Registriert: Mittwoch 19. Mai 2021, 03:40

mirko3107 hat geschrieben: Freitag 9. Juli 2021, 13:51 Könnt ihr euren Streit nicht per PN klären?
Bitte entschuldige, Du hast natürlich Recht.
mirko3107 hat geschrieben: Freitag 9. Juli 2021, 13:51 @Topic: Mein Dataframe wird immer noch nicht beschrieben, hab alle möglichen Optionen probiert.
Verzeihung, welcher Dataframe wird denn nicht beschrieben? Die einzelnen Dateframes aus Deinen Funktionen oder am Ende der "Gesamt-Dataframe", der aus jenen in Deinen Funktionen konkateniert werden soll? Was hast Du bereits ausprobiert, und inwiefern hat es nicht funktioniert? Gab es Fehlermeldungen, und wenn ja, welche? Und wie sieht der Code aus, mit dem Du es ausprobiert hast?
mirko3107
User
Beiträge: 75
Registriert: Freitag 23. April 2021, 15:42

Ich lese aus einer csv ein Dataframe, schreibe Werte in das Dataframe ( hatte ich jedenfalls gedacht) und am Ende sind alle Werte unverändert.

Die Funktion sieht so aus:

Code: Alles auswählen

def yahoo():
    watch = pd.read_csv("watch.csv", usecols=['Ticker', 'Name', 'Price', 'Change', 'Cap', 'EPS', 'Volumen', '52Whigh', '52Wlow', 'Rating'])
    print(watch.head(5))
    rows = len(watch.index)
    while True:
        for i in range(0, 5):
            try:
                ticker = watch['Ticker'].values[i]
                quote_url = 'https://query1.finance.yahoo.com/v7/finance/quote?symbols='+ticker
                quote_req = requests.get(quote_url)
                change = round(quote_req.json()['quoteResponse']['result'][0].get('regularMarketChangePercent', 0),2)
                price = round(quote_req.json()['quoteResponse']['result'][0].get('regularMarketPrice', 0),2)
                volume = quote_req.json()['quoteResponse']['result'][0].get('regularMarketVolume', 0)
                W52high = round(quote_req.json()['quoteResponse']['result'][0].get('fiftyTwoWeekHigh', 0),2)
                W52low = round(quote_req.json()['quoteResponse']['result'][0].get('fiftyTwoWeekLow', 0),2)
                rat1 = quote_req.json()['quoteResponse']['result'][0].get('averageAnalystRating', 'None')
                rating=''
                for i in rat1:
                    if i.isalpha():
                        rating = "".join([rating, i])
                if 'epsCurrentYear' in quote_req.json()['quoteResponse']['result'][0]:
                    eps = round(quote_req.json()['quoteResponse']['result'][0].get('epsCurrentYear', 0),2)
                else:
                    eps = '0'
                cap = round(quote_req.json()['quoteResponse']['result'][0].get('marketCap', 0)/1000000000, 2)
                print(ticker,price,change,cap,eps,volume,W52high,W52low,rating)
                time.sleep(0.5)
                watch.at[i, 'Price'] = price
                watch.at[i, 'Change'] = change
                watch.at[i, 'Cap'] = cap
                watch.at[i, 'EPS'] = eps
                watch.at[i, 'Volumen'] = volume
                watch.at[i, '52Whigh'] = W52high
                watch.at[i, '52Wlow'] = W52low
                watch.at[i, 'Rating'] = rating
            except (KeyError, IndexError, RemoteDataError) as error:
                print(f"Failed reading {ticker}: {error}")
                pass
        print(watch.head(5))
        watch.to_csv('watch2.csv', header=True, index=False, columns=['Ticker', 'Name', 'Price', 'Change', 'Cap', 'EPS', 'Volumen', '52Whigh', '52Wlow', 'Rating'])
        time.sleep(600)
Oben das Dataframe aus der CSV, dann die Werte, die reinsollen und unten das Dataframe, wie es wieder in die CSV geschrieben wird.

Code: Alles auswählen

  Ticker                         Name   Price    Change           Cap    EPS Rating    Volumen  52Whigh  52Wlow
0      A     Agilent Technologies Inc  148.98  0.107505  4.539390e+10   4.14    buy    1973342   149.19   88.07
1     AA                   Alcoa Corp   36.47 -3.823830  6.809861e+09   4.19    buy    8577484    44.42   10.43
2    AAL  American Airlines Group Inc   21.01 -2.188079  1.347546e+10  -8.49   hold   23985527    26.09   10.63
3    AAP     Advance Auto Parts, Inc.  208.70 -1.113480  1.365710e+10  10.91    buy     540639   211.16  131.90
4   AAPL                    Apple Inc  142.02  1.471847  2.369973e+12   5.20    buy  108181793   145.09   89.14
A 149.37 0.36 45.33 4.14 195631 149.71 88.07 Buy
AA 37.6 6.33 7.02 4.27 2698158 44.42 10.43 Buy
AAL 20.91 2.73 13.41 -8.54 9537317 26.09 10.63 Hold
AAP 211.65 2.0 13.85 10.92 118807 212.35 131.9 Buy
AAPL 145.06 1.27 2420.7 5.18 38741349 145.44 89.14 Buy
  Ticker                         Name   Price    Change           Cap    EPS Rating      Volumen  52Whigh  52Wlow
0      A     Agilent Technologies Inc  148.98  0.107505  4.539390e+10   4.14    buy    1973342.0   149.19   88.07
1     AA                   Alcoa Corp   36.47 -3.823830  6.809861e+09   4.19    buy    8577484.0    44.42   10.43
2    AAL  American Airlines Group Inc   21.01 -2.188079  1.347546e+10  -8.49   hold   23985527.0    26.09   10.63
3    AAP     Advance Auto Parts, Inc.  208.70 -1.113480  1.365710e+10  10.91    buy     540639.0   211.16  131.90
4   AAPL                    Apple Inc  142.02  1.471847  2.369973e+12   5.20    buy  108181793.0   145.09   89.14
mirko3107
User
Beiträge: 75
Registriert: Freitag 23. April 2021, 15:42

Fehlermeldung kommt keine.
LukeNukem
User
Beiträge: 232
Registriert: Mittwoch 19. Mai 2021, 03:40

mirko3107 hat geschrieben: Freitag 9. Juli 2021, 16:14 Ich lese aus einer csv ein Dataframe, schreibe Werte in das Dataframe ( hatte ich jedenfalls gedacht) und am Ende sind alle Werte unverändert.

Code: Alles auswählen

  Ticker                         Name   Price    Change           Cap    EPS Rating    Volumen  52Whigh  52Wlow
0      A     Agilent Technologies Inc  148.98  0.107505  4.539390e+10   4.14    buy    1973342   149.19   88.07
1     AA                   Alcoa Corp   36.47 -3.823830  6.809861e+09   4.19    buy    8577484    44.42   10.43
2    AAL  American Airlines Group Inc   21.01 -2.188079  1.347546e+10  -8.49   hold   23985527    26.09   10.63
3    AAP     Advance Auto Parts, Inc.  208.70 -1.113480  1.365710e+10  10.91    buy     540639   211.16  131.90
4   AAPL                    Apple Inc  142.02  1.471847  2.369973e+12   5.20    buy  108181793   145.09   89.14
Könntest Du diesen -- nur diesen -- Teil bitte einmal in eine CSV-Datei schreiben und sie hier als Code posten?
mirko3107
User
Beiträge: 75
Registriert: Freitag 23. April 2021, 15:42

Die gespeicherte CSV sieht genauso aus wie die geladene.

Code: Alles auswählen

Ticker,Name,Price,Change,Cap,EPS,Volumen,52Whigh,52Wlow,Rating
A,Agilent Technologies Inc,148.98,0.107505,45393903616.0,4.14,1973342.0,149.19,88.07,buy
AA,Alcoa Corp,36.47,-3.82383,6809860608.0,4.19,8577484.0,44.42,10.43,buy
AAL,American Airlines Group Inc,21.01,-2.1880789,13475456000.0,-8.49,23985527.0,26.09,10.63,hold
AAP,"Advance Auto Parts, Inc.",208.7,-1.11348,13657098240.0,10.91,540639.0,211.16,131.9,buy
AAPL,Apple Inc,142.02,1.4718473,2369972862976.0,5.2,108181793.0,145.09,89.14,buy
LukeNukem
User
Beiträge: 232
Registriert: Mittwoch 19. Mai 2021, 03:40

mirko3107 hat geschrieben: Freitag 9. Juli 2021, 18:39 Die gespeicherte CSV sieht genauso aus wie die geladene.
Okay, dankeschön. Bitte gib' mir ein paar Minuten, ja? ;-)
mirko3107
User
Beiträge: 75
Registriert: Freitag 23. April 2021, 15:42

werd mich die Tage mal ransetzen und mich mit diesem Vorschlag befassen:

Code: Alles auswählen

QUOTE_URL = "https://query1.finance.yahoo.com/v7/finance/quote"

def query_quote(tickers):
    quote = []
    for ticker in tickers:
        try:
            quote_response = requests.get(QUOTE_URL, params={"symbols": ticker})
            result = quote_response.json()['quoteResponse']['result'][0]
        except (KeyError, IndexError, RemoteDataError) as error:
            print(f"Failed reading {ticker}: {error}")
            quote.append((ticker, 0, 0, 0, 0))
        else:
            quote.append((
                ticker,
                round(result.get('regularMarketPrice', 0),2),
                round(result.get('regularMarketChangePercent', 0),2),
                round(result.get('marketCap', 0)/1000000000, 2),
                round(result.get('epsCurrentYear', 0),2)
            ))
        time.sleep(1)
    return pd.DataFrame(quote, columns=['Ticker', 'Price', 'Change', 'Cap', 'EPS'])
LukeNukem
User
Beiträge: 232
Registriert: Mittwoch 19. Mai 2021, 03:40

mirko3107 hat geschrieben: Freitag 9. Juli 2021, 19:38 werd mich die Tage mal ransetzen und mich mit diesem Vorschlag befassen:
Vielleicht gefällt Dir ja auch das hier:

Code: Alles auswählen

#!/usr/bin/env python
import sys
import time
import logging
import multiprocessing
import concurrent.futures

import requests
import pandas as pd


logging.basicConfig(
    stream=sys.stdout,
    level=logging.INFO,
    format='%(asctime)s ° %(filename)s(%(lineno)d) ° %(levelname)s ° %(message)s'
)


class YahooFun:
    QUOTE_URL = 'https://query1.finance.yahoo.com/v7/finance/quote?symbols={}'
    FILENAME = 'yahoo.csv'

    def __init__(self, filename=None):
        self._filename = filename or self.FILENAME
        self._df = pd.read_csv(self.filename, sep=';')
        self.manager = multiprocessing.Manager()
        self.lock = self.manager.Lock()

    def yahoo(self, idx, ticker):
        try:
            pc_start = time.perf_counter()
            url = self.QUOTE_URL.format(ticker)
            quote_req = requests.get(url, headers={'User-Agent': 'Mozilla/5.0'}).json()['quoteResponse']['result'][0]
            with self.lock:
                self._df.loc[idx, 'Change'] = quote_req.get('regularMarketChangePercent', 0)
                self._df.loc[idx, 'Price'] = quote_req.get('regularMarketPrice', 0)
                self._df.loc[idx, 'EPS'] = quote_req.get('epsCurrentYear', 0)
                self._df.loc[idx, 'Cap'] = quote_req.get('marketCap', 0) / 1000000000
            duration = time.perf_counter() - pc_start
            logging.info('"{}" took {:0.4f} ms'.format(url, duration*1000))
            return duration
        except Exception as e: # not so nice, but for demo purposes...
            logging.exception('Something went terribly wrong')
            return 0.0

    @property
    def df(self):
        return self._df

    @property
    def filename(self):
        return self._filename
    

if __name__ == '__main__':
    yf = YahooFun()
    print(yf.df)
    with concurrent.futures.ThreadPoolExecutor(max_workers=5) as executor:
        futures = [executor.submit(yf.yahoo, idx, yf.df.iloc[idx].Ticker) for idx in yf.df.index]
    logging.info('insgesamt: {} ms'.format(sum([future.result() * 1000 for future in futures])))
    print(yf.df.round(2))
Ich hab' mal die Kommentare weggelassen und das Ganze ein bisschen eingedampft... Wenn Du Fragen hast, bitte tu' Dir keinen Zwang an. ;-)
Sirius3
User
Beiträge: 17710
Registriert: Sonntag 21. Oktober 2012, 17:20

@LukeNukem: wenn man keinen Setter hat, sind die Properties eigentlich überflüssig.
Du hast Dir sicher etwas dabei gedacht, einen Multiprocessing-Lock mit einem ThreadPoolExecutor zu mischen.
submit hat den Vorteil, dass man da einen Rückgabewert benutzen kann, den Du aber nicht wirklich nutzt. Und das Ergebnis eines Requests ist immer noch kein req(uest).
Statt executor.submit und future.result würde man einfach execute.map benutzen.

Code: Alles auswählen

class YahooFun:
    QUOTE_URL = 'https://query1.finance.yahoo.com/v7/finance/quote?symbols={}'
    FILENAME = 'yahoo.csv'

    def __init__(self, filename=None):
        self.filename = filename or self.FILENAME
        self.df = pd.read_csv(self.filename, sep=';')

    def yahoo(self, ticker):
        try:
            url = self.QUOTE_URL.format(ticker)
            response = requests.get(url, headers={'User-Agent': 'Mozilla/5.0'}).json()
            result = response['quoteResponse']['result'][0]
            return [
                quote_req.get('regularMarketChangePercent', 0),
                quote_req.get('regularMarketPrice', 0),
                quote_req.get('epsCurrentYear', 0),
                quote_req.get('marketCap', 0) / 1000000000
            ]
        except Exception as e: # not so nice, but for demo purposes...
            logging.exception('Something went terribly wrong')
            return [0.0] * 4


def main():
    yf = YahooFun()
    print(yf.df)
    with concurrent.futures.ThreadPoolExecutor(max_workers=5) as executor:
        result = list(executor.map(yf.yahoo, yf.df.Ticker))
    df = pd.DataFrame(result, columns=["Change", "Price", "EPS", "Cap"])
    print(df.round(2))

if __name__ == '__main__':
    main()
Aber jetzt braucht ja die yahoo-Methode gar kein self mehr. Wir haben also gar keine Klasse:

Code: Alles auswählen

QUOTE_URL = 'https://query1.finance.yahoo.com/v7/finance/quote?symbols={}'
FILENAME = 'yahoo.csv'

def query_yahoo(ticker):
    try:
        response = requests.get(QUOTE_URL, params={"symbols":ticker}, headers={'User-Agent': 'Mozilla/5.0'}).json()
        result = response['quoteResponse']['result'][0]
        return [
            quote_req.get('regularMarketChangePercent', 0),
            quote_req.get('regularMarketPrice', 0),
            quote_req.get('epsCurrentYear', 0),
            quote_req.get('marketCap', 0) / 1000000000
        ]
    except Exception as e: # not so nice, but for demo purposes...
        logging.exception('Something went terribly wrong')
        return [0.0] * 4


def main():
    yf_df = pd.read_csv(self.filename, sep=';')
    print(yf_df)
    with concurrent.futures.ThreadPoolExecutor(max_workers=5) as executor:
        result = list(executor.map(query_yahoo, yf_df.Ticker))
    df = pd.DataFrame(result, columns=["Change", "Price", "EPS", "Cap"])
    print(df.round(2))

if __name__ == '__main__':
    main()
Am besten fängt man andersherum an, man schreibt Funktionen, und sobald man merkt, das man mehrere Funktionen hat, die den selben Zustand brauchen, packt man die in eine Klasse.
LukeNukem
User
Beiträge: 232
Registriert: Mittwoch 19. Mai 2021, 03:40

Sirius3 hat geschrieben: Freitag 9. Juli 2021, 20:40 @LukeNukem:
Ach, schade, letztens hattest Du mir noch versprochen, daß Du mir nicht mehr schreibst, und ich hatte mich schon gefreut. Aber ich hab' gute Laune und möchte für mich -- zumal ich mich ja dämlicherweise an den Störungen des Threads beteiligt habe -- jetzt erstmal dem TO helfen. Können wir unseren Zwist daher einstweilen zurückstellen?

Wenn wir dem TO geholfen haben, kann ich Dir gerne erklären, welche Gründe ich für jede einzelne der von Dir kritisierten Designentscheidungen hatte und habe. Aber jetzt ist erstmal der TO dran, ja?
mirko3107
User
Beiträge: 75
Registriert: Freitag 23. April 2021, 15:42

LukeNukem hat geschrieben: Freitag 9. Juli 2021, 20:09
mirko3107 hat geschrieben: Freitag 9. Juli 2021, 19:38 werd mich die Tage mal ransetzen und mich mit diesem Vorschlag befassen:
Vielleicht gefällt Dir ja auch das hier:

Ich hab' mal die Kommentare weggelassen und das Ganze ein bisschen eingedampft... Wenn Du Fragen hast, bitte tu' Dir keinen Zwang an. ;-)
Hab bei "self._df = pd.read_csv(self.filename, sep=';')" das Semikolon durch ein Komma ersetzt, jetzt rennt dein Script.
Danke dir für deine Mühe, läuft super und darauf kann ich aufbauen.
Benutzeravatar
__blackjack__
User
Beiträge: 13003
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@LukeNukem: Sirius3 hat mit der Verbesserung des Vorschlags für den TO ja dem TO geholfen. Aber Du siehst das ja gleich wieder als Zwist und persönlichen Angriff auf Dich. Und drückst Dich um eine Antwort die ja auch dem TO helfen würde den Code den er da zu seinem Problem bekommen hat, besser einordnen zu können…
“Most people find the concept of programming obvious, but the doing impossible.” — Alan J. Perlis
LukeNukem
User
Beiträge: 232
Registriert: Mittwoch 19. Mai 2021, 03:40

Sirius3 hat geschrieben: Freitag 9. Juli 2021, 20:40 wenn man keinen Setter hat, sind die Properties eigentlich überflüssig.
Die Properties sorgen dafür, daß die internen Variablen für alle readonly sind, die die Konvention kennen.
Sirius3 hat geschrieben: Freitag 9. Juli 2021, 20:40 Du hast Dir sicher etwas dabei gedacht, einen Multiprocessing-Lock mit einem ThreadPoolExecutor zu mischen.
Ja, MP-Locks funktionieren auch auf Threads. Prozeßlocks sind zwar ein wenig langsamer, dafür aber auch mit Prozessen nutzbar. Ich weiß ja, daß der TO noch ganz andere Dinge vorhat.
Sirius3 hat geschrieben: Freitag 9. Juli 2021, 20:40 submit hat den Vorteil, dass man da einen Rückgabewert benutzen kann, den Du aber nicht wirklich nutzt.
Sicher. Aber ich weiß, daß der TO noch ganz andere Dinge vorhat.
Sirius3 hat geschrieben: Freitag 9. Juli 2021, 20:40 Und das Ergebnis eines Requests ist immer noch kein req(uest).
Nein, das stimmt. Aber wenn Du jemanden etwas zeigen möchtest, funktioniert das mir einem bekannten Aufhänger nun einmal besser.
Sirius3 hat geschrieben: Freitag 9. Juli 2021, 20:40 Statt executor.submit und future.result würde man einfach execute.map benutzen.
Das würde für mein Beispiel passen, klar... jedenfalls, wenn ich nicht wüßte, daß der TO noch sehr viel mehr vorhat.
Sirius3 hat geschrieben: Freitag 9. Juli 2021, 20:40 Am besten fängt man andersherum an, man schreibt Funktionen, und sobald man merkt, das man mehrere Funktionen hat, die den selben Zustand brauchen, packt man die in eine Klasse.
Ich glaube nicht an Standardrezepte. Aussagen wie "man tut dies" oder "man macht nicht jenes" sind mir ausgesprochen suspekt, und ich bin auch nicht irgendein "man".

In meiner Welt verfolgt Softwareentwicklung mehr oder weniger bestimmte -- nicht selten sogar veränderliche -- Ziele.

Meine Implementierung folgt daher einigen Grundgedanken. Erstens möchte ich dem TO gerne verständlich zeigen, wie so etwas elegant, performant, und wartbar geht. Zweitens möchte ich ihm die Möglichkeit geben, auf meinem Code aufzubauen. Drittens weiß ich, daß der TO noch sehr viel mehr vorhat, und möchte ihm passende Schnittstellen und Erweiterungsmöglichkeiten aufzeigen. Viertens halte ich Erweiterbarkeit für eine wichtige Eigenschaft jedes guten Designs -- und wenn jetzt jemand "Overengineering" sagt, disqualifiziert er sich selbst. ;-)
mirko3107
User
Beiträge: 75
Registriert: Freitag 23. April 2021, 15:42

Find deine Hilfe absolut klasse, vielen Dank.

Hab den Part mit self.lock noch um ein paar Werte erweitert.

Code: Alles auswählen

with self.lock:
	self._df.loc[idx, 'Change'] = quote_req.get('regularMarketChangePercent', 0)
	self._df.loc[idx, 'Price'] = quote_req.get('regularMarketPrice', 0)
	self._df.loc[idx, 'EPS'] = quote_req.get('epsCurrentYear', 0)
	self._df.loc[idx, 'Cap'] = quote_req.get('marketCap', 0) / 1000000000
	self._df.loc[idx, 'Volumen'] = quote_req.get('regularMarketVolume', 0)
	self._df.loc[idx, '52Whigh']= quote_req.get('fiftyTwoWeekHigh', 0)
	self._df.loc[idx, '52Wlow'] = quote_req.get('fiftyTwoWeekLow', 0)
	self._df.loc[idx, 'Rating'] = quote_req.get('averageAnalystRating', 'None')
Wie bekomm ich mein gebasteltes hier eingabaut?

Code: Alles auswählen

rat1 = quote_req.json()['quoteResponse']['result'][0].get('averageAnalystRating', 'None')
rating=''
	for i in rat1:
		if i.isalpha():
rating = "".join([rating, i])
Oder gibts da noch bessere Möglichkeit als nur Buchstaben rausfiltern?

Danke
mirko3107
User
Beiträge: 75
Registriert: Freitag 23. April 2021, 15:42

Hab eine andere Quelle für das Rating gefunden:

Code: Alles auswählen

#!/usr/bin/env python
import sys
import time
import logging
import multiprocessing
import concurrent.futures

import requests
import pandas as pd


logging.basicConfig(
    stream=sys.stdout,
    level=logging.INFO,
    format='%(asctime)s ° %(filename)s(%(lineno)d) ° %(levelname)s ° %(message)s'
)


class YahooFun:
    QUOTE_URL = 'https://query1.finance.yahoo.com/v7/finance/quote?symbols={}'
    QUOTE2_URL = 'https://query2.finance.yahoo.com/v10/finance/quoteSummary/{}?formatted=true&crumb=swg7qs5y9UP&lang=en-US&region=US&' \
                 'modules=upgradeDowngradeHistory,recommendationTrend,' \
                 'financialData,earningsHistory,earningsTrend,industryTrend&' \
                 'corsDomain=finance.yahoo.com'
    FILENAME = 'yahoo2.csv'

    def __init__(self, filename=None):
        self._filename = filename or self.FILENAME
        self._df = pd.read_csv(self.filename, sep=',')
        self.manager = multiprocessing.Manager()
        self.lock = self.manager.Lock()

    def yahoo(self, idx, ticker):
        try:
            pc_start = time.perf_counter()
            url = self.QUOTE_URL.format(ticker)
            rating_url = self.QUOTE2_URL.format(ticker)
            quote_req = requests.get(url, headers={'User-Agent': 'Mozilla/5.0'}).json()['quoteResponse']['result'][0]
            quote_rating = requests.get(rating_url, headers={'User-Agent': 'Mozilla/5.0'}).json()['quoteSummary']['result'][0]['financialData']
            with self.lock:
                self._df.loc[idx, 'Change'] = quote_req.get('regularMarketChangePercent', 0)
                self._df.loc[idx, 'Price'] = quote_req.get('regularMarketPrice', 0)
                self._df.loc[idx, 'EPS'] = quote_req.get('epsCurrentYear', 0)
                self._df.loc[idx, 'Cap'] = quote_req.get('marketCap', 0) / 1000000000
                self._df.loc[idx, 'Volumen'] = quote_req.get('regularMarketVolume', 0)
                self._df.loc[idx, '52Whigh']= quote_req.get('fiftyTwoWeekHigh', 0)
                self._df.loc[idx, '52Wlow'] = quote_req.get('fiftyTwoWeekLow', 0)
                self._df.loc[idx, 'Rating'] = quote_rating.get('recommendationKey', 'None')
            duration = time.perf_counter() - pc_start
            logging.info('"{}" took {:0.4f} ms'.format(url, duration*1000))
            return duration
        except Exception as e: # not so nice, but for demo purposes...
            logging.exception('Something went terribly wrong')
            return 0.0

    @property
    def df(self):
        return self._df

    @property
    def filename(self):
        return self._filename


if __name__ == '__main__':
    yf = YahooFun()
    print(yf.df)
    with concurrent.futures.ThreadPoolExecutor(max_workers=5) as executor:
        futures = [executor.submit(yf.yahoo, idx, yf.df.iloc[idx].Ticker) for idx in yf.df.index]
    logging.info('insgesamt: {} ms'.format(sum([future.result() * 1000 for future in futures])))
    csv = (yf.df.round(2))
    csv.to_csv('yahoo2.csv',  header=True, index=False)
Benutzeravatar
sparrow
User
Beiträge: 4164
Registriert: Freitag 17. April 2009, 10:28

Es sieht ein bisschen aus als hätte jemand versucht Java in Python zu programmieren.
mirko3107
User
Beiträge: 75
Registriert: Freitag 23. April 2021, 15:42

@LukeNukem: Wie bau ich da jetzt am besten den Rest vom Script ein?
LukeNukem
User
Beiträge: 232
Registriert: Mittwoch 19. Mai 2021, 03:40

mirko3107 hat geschrieben: Samstag 10. Juli 2021, 11:12

Code: Alles auswählen

rat1 = quote_req.json()['quoteResponse']['result'][0].get('averageAnalystRating', 'None')
rating=''
	for i in rat1:
		if i.isalpha():
rating = "".join([rating, i])
Oder gibts da noch bessere Möglichkeit als nur Buchstaben rausfiltern?
Ungetestet:

Code: Alles auswählen

def filter_alpha(value):
    if isinstance(value, (bytes, str)):
        return ''.join([c for c in value if c.isalpha()])
    return value
    
df.rating = df.rating.apply(filter_alpha).astype('category')
Das ".astype()" muß nicht, konvertiert die Daten aber in kategorische Variablen, siehe dazu [1].

[1] https://pandas.pydata.org/pandas-docs/s ... rical.html
LukeNukem
User
Beiträge: 232
Registriert: Mittwoch 19. Mai 2021, 03:40

mirko3107 hat geschrieben: Sonntag 11. Juli 2021, 19:00 @LukeNukem: Wie bau ich da jetzt am besten den Rest vom Script ein?
Du hast ja mehrere Teile, die die Daten aus unterschiedlichen Quellen ziehen und dann, zumindest teilweise, auf eine recht ähnliche Art konvertieren. Also nimmst Du Dir Deine anderen Programmteile und baust sie nach dem Vorbild um, das ich gezeigt habe. Das baust Du dann in den Hauptteil -- also: dem Teil unter "if __name__ ==..." ein, erzeugst aus Deinen neuen Klassen (bei mir: "YahooFun") also Instanzen (bei mir: "yf = YahooFun()"), übergibst die "Arbeitsfunktionen" (bei mir: "yahoo()") Deinem ThreadPoolExecutor und hängst die future-Objekte mit += an die Variable "futures" an.

Am Ende -- also: wenn alles durchgelaufen ist und alle future-Objekte in "futures" mit "result()" ihre Ergebnisse geliefert haben -- ziehst Du aus den genannten Instanzen dann Deine Pandas-DataFrames, wie ich in der letzten Zeile, baust mit "pandas.concat()" einen großen Ergebnis-Dataframe, und dann kannst Du damit viele lustige Dinge machen: sie einfach schnöde ausgeben, mit Altair oder Bokeh hübsche Plots daraus erzeugen, ganz wie Du lustig bist. Vorher würde ich Dir allerdings empfehlen, mal ein Python- und ein Pandas-Tutorial durchzuarbeiten... Viel Erfolg! ;-)
mirko3107
User
Beiträge: 75
Registriert: Freitag 23. April 2021, 15:42

LukeNukem hat geschrieben: Sonntag 11. Juli 2021, 22:40
mirko3107 hat geschrieben: Samstag 10. Juli 2021, 11:12

Code: Alles auswählen

rat1 = quote_req.json()['quoteResponse']['result'][0].get('averageAnalystRating', 'None')
rating=''
	for i in rat1:
		if i.isalpha():
rating = "".join([rating, i])
Oder gibts da noch bessere Möglichkeit als nur Buchstaben rausfiltern?
Ungetestet:

Code: Alles auswählen

def filter_alpha(value):
    if isinstance(value, (bytes, str)):
        return ''.join([c for c in value if c.isalpha()])
    return value
    
df.rating = df.rating.apply(filter_alpha).astype('category')
Das ".astype()" muß nicht, konvertiert die Daten aber in kategorische Variablen, siehe dazu [1].

[1] https://pandas.pydata.org/pandas-docs/s ... rical.html
Wenn ich über die gleiche URL wie die anderen Werte den Wert "averageAnalystRating" abfrage, bekomm ich ab der Hälfte der Ticker-Werte keinen Wert mehr ausgelesen,
alle anderen funktionieren weiterhin. Der Wert verschwindet scheinbar, auch wenn man im Browser den Link zu oft abfragt.
Ich bleib dann bei meiner anderen URL, die scheint dauerhaft zu funktionieren.
Antworten