updated info at bottom
I have a group from a df.groupby that looks like this:
stop_id stop_name arrival_time departure_time stop_sequence
0 87413013 Gare de Le Havre 05:20:00 05:20:00 0.0
1 87413344 Gare de Bréauté-Beuzeville 05:35:00 05:36:00 1.0
2 87413385 Gare de Yvetot 05:49:00 05:50:00 2.0
3 87411017 Gare de Rouen-Rive-Droite 06:12:00 06:15:00 3.0
4 87384008 Gare de Paris-St-Lazare 07:38:00 07:38:00 4.0
I want to loop each row and use "stop_name" as the location of departure
and then get the following "stop_name" of the next rows as the location of arrival.
Finally I use the below func in order to parse the times and calc the trip duration in seconds.
def timestrToSeconds(timestr):
ftr = [3600,60,1]
return sum([a*b for a,b in zip(ftr, map(int,timestr.split(':')))])
The output is expected to be an array with all possible combinations like below :
result = [
('Gare de Le Havre', 'Gare de Bréauté-Beuzeville', 900),
('Gare de Le Havre', 'Gare de Yvetot', 1740),
('Gare de Le Havre', 'Gare de Rouen-Rive-Droite', 3120),
('Gare de Le Havre', 'Gare de Paris-St-Lazare', 8280),
('Gare de Bréauté-Beuzeville', 'Gare de Yvetot', 780),
('Gare de Bréauté-Beuzeville', 'Gare de Rouen-Rive-Droite', 2160),
('Gare de Bréauté-Beuzeville', 'Gare de Paris-St-Lazare', 7320),
('Gare de Yvetot', 'Gare de Rouen-Rive-Droite', 3120),
('Gare de Yvetot', 'Gare de Paris-St-Lazare', 6480),
('Gare de Rouen-Rive-Droite', 'Gare de Paris-St-Lazare', 4980),
]
I have tried with nested loops but ended up being too abstract for me.
Any advice is more than welcome
UPDATE
Mazhar's solution seems to work find on a single group, but when i loop through my groupby like this :
timeBetweenStops = []
for group_name, group in xgrouped:
group.arrival_time = pd.to_timedelta(group.arrival_time)
group.departure_time = pd.to_timedelta(group.departure_time)
new_df = group['departure_time'].apply(lambda x: (
group['arrival_time']-x).apply(lambda y: y.total_seconds()))
new_df.index = group.stop_name
new_df.columns = group.stop_name
for i in new_df.index:
for j in new_df.columns:
if new_df.loc[i, j] > 0:
r = (i, j, new_df.loc[i, j])
timeBetweenStops.append(r)
I get the following error:
ValueError Traceback (most recent call last)
<ipython-input-196-ec050382d2b5> in <module>
14 for i in new_df.index:
15 for j in new_df.columns:
---> 16 if new_df.loc[i, j] > 0:
17 r = (i, j, new_df.loc[i, j])
18 timeBetweenStopsA.append(r)
~/opt/anaconda3/lib/python3.8/site-packages/pandas/core/generic.py in __nonzero__(self)
1476
1477 def __nonzero__(self):
-> 1478 raise ValueError(
1479 f"The truth value of a {type(self).__name__} is ambiguous. "
1480 "Use a.empty, a.bool(), a.item(), a.any() or a.all()."
ValueError: The truth value of a Series is ambiguous. Use a.empty, a.bool(), a.item(), a.any() or a.all().
I have tried to use if np.where(new_df.loc[i, j] > 0): , but then i get plenty of incoherences in my result.
Convert your time columns to Timedelta with to_timedelta
df['arrival_time'] = pd.to_timedelta(df['arrival_time'])
df['departure_time'] = pd.to_timedelta(df['departure_time'])
Now use itertools.combinations to generate all combinations:
from itertools import combinations
comb = lambda x: [
(x.loc[i1, 'stop_name'], x.loc[i2, 'stop_name'],
int((x.loc[i2, 'departure_time'] - x.loc[i1, 'arrival_time']).total_seconds()))
for i1, i2 in combinations(x.index, 2)
]
For your current group:
>>> comb(df)
[('Gare de Le Havre', 'Gare de Bréauté-Beuzeville', 960),
('Gare de Le Havre', 'Gare de Yvetot', 1800),
('Gare de Le Havre', 'Gare de Rouen-Rive-Droite', 3300),
('Gare de Le Havre', 'Gare de Paris-St-Lazare', 8280),
('Gare de Bréauté-Beuzeville', 'Gare de Yvetot', 900),
('Gare de Bréauté-Beuzeville', 'Gare de Rouen-Rive-Droite', 2400),
('Gare de Bréauté-Beuzeville', 'Gare de Paris-St-Lazare', 7380),
('Gare de Yvetot', 'Gare de Rouen-Rive-Droite', 1560),
('Gare de Yvetot', 'Gare de Paris-St-Lazare', 6540),
('Gare de Rouen-Rive-Droite', 'Gare de Paris-St-Lazare', 5160)]
On many groups:
>>> df.groupby(...).apply(comb)
1 [(Gare de Le Havre, Gare de Bréauté-Beuzeville...
dtype: object
df.arrival_time = pd.to_timedelta(df.arrival_time)
df.departure_time = pd.to_timedelta(df.departure_time)
new_df = df['departure_time'].apply(lambda x: (
df['arrival_time']-x).apply(lambda y: y.total_seconds()))
new_df.index = df.stop_name
new_df.columns = df.stop_name
for i in new_df.index:
for j in new_df.columns:
if new_df.loc[i, j] > 0:
print(i, j, new_df.loc[i, j])
Until you update your question so this code can be checked with real data, here is one solution:
all_combs=combinations(df['stop_name'].to_list())
results=[]
for c in all_combs:
results.append((*c,abs(df.loc[df['stop_name']==c[0],'arrival_time']-df.loc[df['stop_name']==c[1],'arrival_time'])))
That's assum,ing that arrival_time (or whatever desired column you try to look into) is already in pandas.timedate format. If not, take a look here and convert to timedate:
Pandas convert Column to time
Note: This code works assuming that you have one value for each location in the column.
I don't think you can escape nested loops here. It may be possible to do it using list comprehension but it will be even more abstract...
You can get your result with the following code:
resultat = []
for i, ligne1 in df.iterrows():
depart = ligne1.stop_name
departure_time = ligne1.departure_time
for _, ligne2 in df.iloc[(i + 1):].iterrows():
arrivee = ligne2.stop_name
arrival_time = ligne2.arrival_time
duree = timestrToSeconds(arrival_time) - timestrToSeconds(departure_time)
resultat = resultat + [(depart, arrivee, duree)]
(Edit) This code works assuming that stations are ordered from departure to arrival. If it's not the case, you can order the dataframe with:
df = df.sort_values(by = 'departure_time')
I think you can do this without loops, substituting a heavy-handed cross join instead:
from io import StringIO
import pandas
import numpy
filedata = StringIO("""\
stop_id stop_name arrival_time departure_time stop_sequence
87413013 Gare de Le Havre 05:20:00 05:20:00 0.0
87413344 Gare de Bréauté-Beuzeville 05:35:00 05:36:00 1.0
87413385 Gare de Yvetot 05:49:00 05:50:00 2.0
87411017 Gare de Rouen-Rive-Droite 06:12:00 06:15:00 3.0
87384008 Gare de Paris-St-Lazare 07:38:00 07:38:00 4.0
""")
df = (
pandas.read_csv(filedata, sep="\s\s+", parse_dates=["arrival_time", "departure_time"])
)
results = (
df.merge(df, how="cross")
.loc[lambda df: df["stop_sequence_x"] < df["stop_sequence_y"]]
.assign(travel_time_seconds=lambda df:
df["arrival_time_y"]
.sub(df["departure_time_x"])
.dt.total_seconds()
)
.loc[:, ["stop_name_x", "stop_name_y", "travel_time_seconds"]]
.reset_index(drop=True)
)
and that gives me:
stop_name_x stop_name_y travel_time_seconds
0 Gare de Le Havre Gare de Bréauté-Beuzeville 900.0
1 Gare de Le Havre Gare de Yvetot 1740.0
2 Gare de Le Havre Gare de Rouen-Rive-Droite 3120.0
3 Gare de Le Havre Gare de Paris-St-Lazare 8280.0
4 Gare de Bréauté-Beuzeville Gare de Yvetot 780.0
5 Gare de Bréauté-Beuzeville Gare de Rouen-Rive-Droite 2160.0
6 Gare de Bréauté-Beuzeville Gare de Paris-St-Lazare 7320.0
7 Gare de Yvetot Gare de Rouen-Rive-Droite 1320.0
8 Gare de Yvetot Gare de Paris-St-Lazare 6480.0
9 Gare de Rouen-Rive-Droite Gare de Paris-St-Lazare 4980.0
Related
import re, datetime, time
input_text = "tras la aparicion del objeto misterioso el 2022-12-30 visitamos ese sitio nuevamente revisando detras de los arboles pero recien tras 3 dias ese objeto aparecio de nuevo tras 2 arboles" #example 1
input_text = "luego el 2022-11-15 fuimos nuevamente a dicho lugar pero nada ocurrio y 3 dias despues ese objeto aparecio en el cielo durante el atardecer de aquel dia de verano" #example 2
input_text = "Me entere del misterioso suceso ese 2022-11-01 y el 2022-11-15 fuimos al monte pero nada ocurrio, pero luego de 13 dias ese objeto aparecio en el cielo" #example 3
identified_referencial_date = r"(?P<year>\d*)-(?P<month>\d{2})-(?P<startDay>\d{2})" #obtained with regex capture groups
# r"(?:luego[\s|]*de[\s|]*unos|luego[\s|]*de|pasados[\s|]*ya[\s|]*unos|pasados[\s|]*unos|pasados[\s|]*ya|pasados|tras[\s|]*ya|tras)[\s|]*\d*[\s|]*(?:días|dias|día|dia)"
# r"\d*[\s|]*(?:días|dias|día|dia)[\s|]*(?:despues|luego)"
n = #the number of days that in this case should increase
indicated_date_relative_to_another = str(identified_date_in_date_format - datetime.timedelta(days = int(n) ))
input_text = re.sub(identified_referencial_date, indicated_date_relative_to_another, input_text)
print(repr(input_text)) # --> output
The objective is that if a day is indicated first in the format year-month-day (are integers separated by hyphens in that order) \d*-\d{2}-\d{2} and then it says that n amount of days have passed, so you would have to replace that sentence with year-month-day+n
luego de unos 3 dias ---> add 3 days to a previous date
luego de 6 dias ---> add 6 days to a previous date
pasados ya 13 dias ---> add 13 days to a previous date
pasados ya unos 48 dias ---> add 48 days to a previous date
pasados unos 36 dias ---> add 36 days to a previous date
pasados 9 dias ---> add 9 days to a previous date
tras ya 2 dias ---> add 2 days to a previous date
tras 32 dias ---> add 32 days to a previous date
3 dias despues ---> add 3 days to a previous date
3 dias luego ---> add 3 days to a previous date
Keep in mind that in certain cases, increasing the number of days could also change the number of the month or even the year, as in example 1.
Outputs that I need obtain in each case:
"tras la aparicion del objeto misterioso el 2022-12-30 visitamos ese sitio nuevamente revisando detras de los arboles pero recien 2023-01-02 ese objeto aparecio de nuevo tras 2 arboles" #for the example 1
"luego el 2022-11-15 fuimos nuevamente a dicho lugar pero nada ocurrio y 2022-11-18 ese objeto aparecio en el cielo durante el atardecer de aquel dia de verano" #for the example 2
"Me entere del misterioso suceso ese 2022-11-01 y el 2022-11-15 fuimos al monte pero nada ocurrio, pero 2022-11-28 ese objeto aparecio en el cielo" #for the example 3
Here is a regex solution you could use:
([12]\d{3}-[01]\d-[0-3]\d)(\D*?)(?:(?:luego de|pasados|tras)(?: ya)?(?: unos)? (\d+) dias|(\d+) dias (?:despues|luego))
This regex requires that there are no other digits between the date and the days. It also is a bit loose on grammar. It would also match "luego de ya 3 dias". You can of course make it more precise with a longer regex, but you get the picture.
In a program:
from datetime import datetime, timedelta
import re
def add(datestr, days):
return (datetime.strptime(datestr, "%Y-%m-%d")
+ timedelta(days=int(days))).strftime('%Y-%m-%d')
input_texts = [
"tras la aparicion del objeto misterioso el 2022-12-30 visitamos ese sitio nuevamente revisando detras de los arboles pero recien tras 3 dias ese objeto aparecio de nuevo tras 2 arboles",
"luego el 2022-11-15 fuimos nuevamente a dicho lugar pero nada ocurrio y 3 dias despues ese objeto aparecio en el cielo durante el atardecer de aquel dia de verano",
"Me entere del misterioso suceso ese 2022-11-01 y el 2022-11-15 fuimos al monte pero nada ocurrio, pero luego de 13 dias ese objeto aparecio en el cielo"
]
for input_text in input_texts:
result = re.sub(r"([12]\d{3}-[01]\d-[0-3]\d)(\D*?)(?:(?:luego de|pasados|tras)(?: ya)?(?: unos)? (\d+) dias|(\d+) dias (?:despues|luego))",
lambda m: m[1] + m[2] + add(m[1], m[3] or m[4]),
input_text)
print(result)
I have this below DataFrame:
df = pd.DataFrame({'DC':['Alexandre', 'Alexandre', 'Afonso de Sousa', 'Afonso de Sousa','Afonso de Sousa'],
'PN':['Farmacia Ekolelo', 'Farmacia Havemos De Voltar', 'Farmacia Gloria', 'Farmacia Mambofar','Farmacia Metamorfose'],
'PC':['C-HO-002815', 'C-HO-005192', 'C-HO-002719', 'C-HO-003030','C-SCC-012430'],
'KCP':['NA', 'DOMINGAS PAULO', 'HELDER', 'Mambueno','RITA'],
'MBN':['NA', 'NA', 29295486345, 9.40407E+11,2.92955E+11]})
Trying to convert data into below format.
By grouping DC column needs to transpose other columns as per above format.
You can group by DC then aggregate with list. From there you can concat the dataframes created from the aggregated lists:
import pandas as pd
df = pd.DataFrame({'DC':['Alexandre', 'Alexandre', 'Afonso de Sousa', 'Afonso de Sousa','Afonso de Sousa'],
'PN':['Farmacia Ekolelo', 'Farmacia Havemos De Voltar', 'Farmacia Gloria', 'Farmacia Mambofar','Farmacia Metamorfose'],
'PC':['C-HO-002815', 'C-HO-005192', 'C-HO-002719', 'C-HO-003030','C-SCC-012430'],
'KCP':['NA', 'DOMINGAS PAULO', 'HELDER', 'Mambueno','RITA'],
'MBN':['NA', 'NA', 29295486345, 9.40407E+11,2.92955E+11]})
df = df.groupby('DC', as_index=False).agg(list)
#print(df)
df_out = pd.concat([df[['DC']]] +
[
pd.DataFrame(l := df[col].to_list(),
columns=[f'{col}_{i}' for i in range(1, max(len(s) for s in l) + 1)]
) for col in df.columns[1:]
],
axis=1)
Note: the assignment in the comprehension l := df[col].to_list() only works for Python versions >= 3.8.
This will give you:
DC PN_1 PN_2 PN_3 ... KCP_3 MBN_1 MBN_2 MBN_3
0 Afonso de Sousa Farmacia Gloria Farmacia Mambofar Farmacia Metamorfose ... RITA 29295486345 940407000000.0 2.929550e+11
1 Alexandre Farmacia Ekolelo Farmacia Havemos De Voltar None ... None NA NA NaN
You can then sort the columns with your own function:
def sort_columns(col_lbl):
col, ind = col_lbl.split('_')
return (int(ind), df.columns.to_list().index(col))
df_out.columns = ['DC'] + sorted(df_out.columns[1:].to_list(), key=sort_columns)
Output:
DC PN_1 PC_1 KCP_1 ... PN_3 PC_3 KCP_3 MBN_3
0 Afonso de Sousa Farmacia Gloria Farmacia Mambofar Farmacia Metamorfose ... RITA 29295486345 940407000000.0 2.929550e+11
1 Alexandre Farmacia Ekolelo Farmacia Havemos De Voltar None ... None NA NA NaN
After downloading Facebook data, they provide json files with your post information. I read the json and dataframe with pandas. Now I want to count the characters of every post I made. The posts are in: df['data'] like: [{'post': 'Happy bday Raul'}].
I want the output to be the count of characters of: "Happy bday Raul" which will be 15 in this case or 7 in the case of "Morning" from [{'post': 'Morning'}].
df=pd.read_json('posts_1.json')
The columns are Date and Data with this format:
Date Data
01-01-2020 *[{'post': 'Morning'}]*
10-03-2020 *[{'post': 'Happy bday Raul'}]*
17-03-2020 *[{'post': 'This lockdown is sad'}]*
I tried to count the characters of this [{'post': 'Morning'}] by doing this
df['count']=df['data'].str.len()
But it's not working as result in "1".
I need to extract the value of the dictionary and do the len to count the characters. The output will be:
Date Data COUNT
01-01-2020 *[{'post': 'Morning'}]* 5
10-03-2020 *[{'post': 'Happy bday Raul'}]* 15
17-03-2020 *[{'post': 'This lockdown is sad'}]* 20
EDITED:
Used to_dict()
df11=df_post['data'].to_dict()
Output
{0: [{'post': 'Feliz cumpleaños Raul'}],
1: [{'post': 'Muchas felicidades Tere!!! Espero que todo vaya genial y siga aún mejor! Un beso desde la Escandinavia profunda'}],
2: [{'post': 'Hola!\nUna investigadora vendrá a finales de mayo, ¿Alguien tiene una habitación libre en su piso para ella? Many Thanks!'}],
3: [{'post': '¿Cómo va todo? Se que muchos estáis o estábais por Galicia :D\n\nOs recuerdo, el proceso de Matriculación tiene unos plazos concretos: desde el lunes 13 febrero hasta el viernes 24 de febrero.'}]
}
You can access the value of the post key for each row using list comprehension and count the length with str.len():
In one line of code, it would look like this:
df[1] = pd.Series([x['post'] for x in df[0]]).str.len()
This would also work, but I think it would be slower to execute:
df[1] = df[0].apply(lambda x: x['post']).str.len()
Full reproducible code below:
df = pd.DataFrame({0: [{'post': 'Feliz cumpleaños Raul'}],
1: [{'post': 'Muchas felicidades Tere!!! Espero que todo vaya genial y siga aún mejor! Un beso desde la Escandinavia profunda'}],
2: [{'post': 'Hola!\nUna investigadora vendrá a finales de mayo, ¿Alguien tiene una habitación libre en su piso para ella? Many Thanks!'}],
3: [{'post': '¿Cómo va todo? Se que muchos estáis o estábais por Galicia :D\n\nOs recuerdo, el proceso de Matriculación tiene unos plazos concretos: desde el lunes 13 febrero hasta el viernes 24 de febrero.'}]
})
df = df.T
df[1] = [x['post'] for x in df[0]]
df[2] = df[1].str.len()
df
Out[1]:
0 \
0 {'post': 'Feliz cumpleaños Raul'}
1 {'post': 'Muchas felicidades Tere!!! Espero qu...
2 {'post': 'Hola!
Una investigadora vendrá a fi...
3 {'post': '¿Cómo va todo? Se que muchos está...
1 2
0 Feliz cumpleaños Raul 22
1 Muchas felicidades Tere!!! Espero que todo vay... 112
2 Hola!\nUna investigadora vendrá a finales de ... 123
3 ¿Cómo va todo? Se que muchos estáis o está... 195
I'm web scraping to get information about articles from a website, for that text I want to save the header of the text and the description as key and value in a dictionary.
When I run the code, I get an error unhashable type: 'list'. What I can do to fix this?
This is all the code:
import requests
import bs4
from bs4 import BeautifulSoup
import smtplib
import os
bodyDict = dict()
newslist = list()
body = "NEWS:\n"
web = requests.get("http://www.infobolsa.es/news")
soup = bs4.BeautifulSoup(web.text, 'lxml')
for item in soup.find_all("article"):
newslist.append(item.text.split("\n"))
for row in newslist:
bodyDict[newslist[1]]=newslist[3]
print(bodyDict)
This can be achieved using the code below. We need to get the header (in <h3> tags) and the value (in the last <p>) tag for each <article> tag in the page. I've assumed that you want to ignore header tags that have the class 'video'.
import requests
import bs4
bodyDict = dict()
web = requests.get("http://www.infobolsa.es/news")
soup = bs4.BeautifulSoup(web.text, 'lxml')
for item in soup.find_all("article"):
# Find the header
header = item.find('h3')
# Ignore headers that are videos
if 'video' in header.get('class', []):
continue
# Get the value of the last p tag
value = item.find_all('p')[-1].text
# Append to dictionary
bodyDict[header.text] = value
Which gives us:
{'PharmaMar recibe 200 millones de dólares como pago inicial del acuerdo firmado con Jazz': 'PharmaMar y Jazz firmaron el pasado 19 de diciembre de 2019 un acuerdo de licencia en exclusiva para la comercialización de lurbinectedina en Estados Unidos.\xa0PharmaMar también podrá recibir hasta 800 millones de dólares adicionales en potenciales pagos por hitos, además de los royalties sobre las ventas netas.',
'El Ibex 35, el índice con mayor fortaleza de Europa hoy': 'Los índices europeos y sus futuros, futuro del Dax y futuro del Euro Stoxx 50, a media mañana están con subidas, pero han perdido el rumbo y están a la espera de lo que pueda hacer el futuro del SP500 que les sirva de\xa0 guía para tomar una dirección. El Ibex 35 es el más destacado gracias a que el Banco Santander lidera las subidas (+3,68%).',
'Eurostoxx 50: primer objetivo 3.730 puntos': 'Ángel Cotera, especialista de mercados de BBVA Trader analiza desde un punto de vista técnico el Eurostoxx 50.',
'Grenergy tiene la confianza de Caixabank y su recomendación de compra': 'Los analistas otorgan un precio objetivo\xa0de 18,65 euros la compañía de renovables, lo que supone un recorrido alcista del 21,10% para los títulos de la\xa0compañía de energías renovables en el Mercado Continuo.',
'UBS eleva la recomendación de Bankinter en un momento correctivo en bolsa': 'El organismo cree que con el mínimo histórico al que cotizan actualmente la acciones cualquier riesgo está "mejor reflejado". Sube su recomendación hasta neutral.',
'La FED afronta su primera reunión del año sin la presión de los mercados ni de Trump': 'Juan Ramón Casanovas, Head of Private Portfolio Management, Bank Degroof Petercam Spain valora las opciones que tiene Jerome Powell en la primera reunión de la FED del año.',
'PharmaMar tendrá en China la tecnología para detectar el coronavirus en 6 semanas': 'La biotecnológica española cuenta con la tecnología para detectar el virus y está trabajando para adaptar las máquinas\xa0de diagnóstico de Genomica con las que cuenta en Wuhan.',
'Airbus provisiona 3.600 millones para pagar posibles sanciones por corrupción': 'Airbus ha provisionado\xa03.600 millones de euros\xa0para el pago de posibles sanciones a las autoridades francesas, británicas y estadounidenses. Las investigaciones emprendidas por dichas autoridades conciernen a acusaciones de soborno y de corrupción así como a imprecisiones en declaraciones hechas a las autoridades de los Estados Unidos de acuerdo con el International Traffic in Arms Regulations (ITAR).',
'Logista aumenta su beneficio un 3,3% hasta los 37,2 millones': 'El distribuidor de productos minoristas Logista alcanzó un beneficio neto en su\xa0primer trimestre fiscal\xa0del año (octubre-diciembre) de 37,2 millones de euros, lo que supone un aumento del 3,3%.',
'Santander solo aspira a rebotes a corto plazo': 'Santander continúa inmerso en una clara tendencia bajista de largo plazo que permanece vigente mientras el precio no consiga superar 3,9395 / 3,8655. Si el precio consigue respetar los mínimos del año pasado y el volumen aumenta se avanzaría en la construcción de un suelo. \xa0',
'Banco Santander lleva al Ibex 35 por encima de los 9.500 puntos': 'El Ibex 35 arranca la sesión con subidas del 0,49% que le llevan a los 9.532 puntos. Subidas que lideran los títulos de Banco\xa0 Santander que, tras la publicación de sus resultados, ha llegado a subir más de un 3% en la apertura.',
'El mayor banco de Canadá sobrepondera ahora las acciones de Repsol': 'Los analistas de\xa0Royal Bank of Canada (RBC) han elevado este miércoles\xa0la recomendación de Repsol de "infraponderar" hasta\xa0"sobreponderar", ya que según el mayor banco canadiense\xa0la petrolera española ha empezado a mostrar una mejor relación riesgo-rentabilidad que la mayoría de sus\xa0competidoras.',
'Las bolsas europeas abren con tono mixto pendientes de China y la FED': 'Los índices de las principales bolsas europeas comienzan la sesión con tono mxixto. El DAX sube un 0,04%, hasta los 13.328 puntos; el FTSE -100 arranca la sesión con subidas del 0,13%, hasta los 7.491 puntos. El CAC-40 abre en los 5.926 pntos mientras que el Eurostoxx 50 abre en los 3.722 puntos tras avanzar ligeramente. El FTSE MiB en negativo sobre los 24.024 puntos. Hoy toda la atención sobre China y la primera reunión del año de la FED.',
'Banco Santander reduce un 17% su beneficio en 2019, hasta los 6.515 millones': 'Banco Santander ha anunciado una reducción del 17% en su beneficio atribuido en 2019, hasta los 6.515 millones. Y eso a pesar de que en el cuarto trimestre la entidad incrementó en un 35% su beneficio logrando así el mayor beneficio atribuido de la historia, en los 2.783 millones. La compañía propone aumentar el dividendo en efecto.',
'MAB: ventajas de las empresas al cotizar en Bolsa': 'Las pymes son actrices protagonistas de la economía española. Sólo alguien que no sepa de economía las consideraría actrices de reparto, ya que emplean al 80% de nuestra fuerza laboral y representan el 65% de nuestro PIB. Cuando necesitan financiación, visibilidad, liquidez, y el resto de ventajas que conlleva cotizar, disponen de una plataforma hecha a su medida: el Mercado Alternativo Bursátil (MaB). Sus integrantes volverían a dar el salto sin dudarlo, pero se quejan de que le siguen faltando tamaño y, por ende, liquidez.',
'Tesla sigue alcista tras superar en Bolsa a Volkswagen': '\xa0',
'"Los sectores más atractivos y que más nos gustan son los más caros: tecnología y salud"': 'Hablamos de los mercados con Josep Bayarri, director de productos, análisis e inversiones de Arquia Banca.\xa0',
'"Creemos que es más fácil, en un año como este, invertir en pequeñas y medianas compañías"': 'Hablamos de los mercados y para ello contamos con la presencia de Álvaro de Liniers, responsable de desarrollo de negocio de Groupama AM para España.',
'Reunión de la Fed y resultados de Logista y Santander, en la agenda del día': 'Este miércoles los inversores y analistas estarán muy pendientes del índice de confianza del consumidor Gfk, decisión de tipos de interés de la Fed, variación de ventas de viviendas pendientes y conferencia de prensa de la\xa0Comité Federal del Mercado Abierto de la Reserva Federal.'}
I have this large string:
s = '''Vaya ir VMM03S0 0.427083
mañanita mañana RG 0.796611
, , Fc 1
buscando buscar VMG0000 1
la lo PP3FSA00 0.0277039
encontramos encontrar VMIP1P0 0.65
. . Fp 1
Pero pero CC 0.999764
vamos ir VMIP1P0 0.655914
a a SPS00 0.996023
lo el DA0NS0 0.457533
que que PR0CN000 0.562517
interesa interesar VMIP3S0 0.994868
LO_QUE_INTERESA_La lo_que_interesa_la NP00000 1
lavadora lavador AQ0FS0 0.585262
tiene tener VMIP3S0 1
una uno DI0FS0 0.951575
clasificación clasificación NCFS000 1
A+ a+ NP00000 1
, , Fc 1
de de SPS00 0.999984
las el DA0FP0 0.970954
que que PR0CN000 0.562517
ahorran ahorrar VMIP3P0 1
energía energía NCFS000 1
, , Fc 1
si si CS 0.99954
me me PP1CS000 0.89124
no no RN 0.998134
equivoco equivocar VMIP1S0 1
. . Fp 1
Lava lavar VMIP3S0 0.397388
hasta hasta SPS00 0.957698
7 7 Z 1
kg kilogramo NCMN000 1
, , Fc 1
no no RN 0.998134
está estar VAIP3S0 0.999201
, , Fc 1
se se P00CN000 0.465639
le le PP3CSD00 1
veía ver VMII3S0 0.62272
un uno DI0MS0 0.987295
gran gran AQ0CS0 1
tambor tambor NCMS000 1
( ( Fpa 1
de de SPS00 0.999984
acero acero NCMS000 0.973481
inoxidable inoxidable AQ0CS0 1
) ) Fpt 1
y y CC 0.999962
un uno DI0MS0 0.987295
error error NCFSD23 0.234930
error error VMDFG34 0.98763
consumo consumo NCMS000 0.948927
máximo máximo AQ0MS0 0.986111
de de SPS00 0.999984
49 49 Z 1
litros litro NCMP000 1
error error DI0S3DF 1
Mandos mandos NP00000 1
intuitivos intuitivo AQ0MP0 1
, , Fc 1
todo todo PI0MS000 0.43165
muy muy RG 1
bien bien RG 0.902728
explicado explicar VMP00SM 1
, , Fc 1
jamas jamas RG 0.343443
nada nada PI0CS000 0.850279
que que PR0CN000 0.562517
de de SPS00 0.999984
nunca nunca RG 0.903
casa casa NCFS000 0.979058
de de SPS00 0.999984
mis mi DP1CPS 0.995868
error error VM9032 0.234323
string string VMWEOO 0.03444
padres padre NCMP000 1
Además además NP00000 1
incluye incluir VMIP3S0 0.994868
la el DA0FS0 0.972269
tecnología tecnología NCFS000 1
error errpr RG2303 1
Textileprotec textileprotec NP00000 1
que que PR0CN000 0.562517
protege proteger VMIP3S0 0.994868
nuestras nuestro DP1FPP 0.994186
ninguna ninguno DI0S3DF 0.345344
falla falla NCFSD23 1
prendas prenda NCFP000 0.95625
más más RG 1
preciadas preciar VMP00PF 1
jamas jamas RG2303 1
string string VM9032 0.234323
nunca nunca RG 0.293030
string string VM 0.902333
no no RN
le le PP004DF 0.390230
falla fallar VM0FD00 0.99033
. . Fp 1'''
I would like to extract in a list the second word from left to right and its id that holds this ids pattern: RN_ _ _ _ _, PP_ _ _ _ _, VM_ _ _ _ _. This ids must be together. For example:
no no RN 0.90383
le le PPSDF23 0.902339
falla fallar VM00DKE 0.9045
This is the pattern I would like to match, since they are together and the ids have the RN_ _ _ _ _, PP_ _ _ _ _, VM_ _ _ _ _ order this should be the output given the s string:
[('no RN', 'le PP004DF', 'fallar VM0FD00')]
This is what I tried:
together__ = re.findall(r'(?s)(\w+\s+RN)(?:(?!\s(?:RN|PP|VM)).)*?(\w+\s+PP\w+)(?:(?!\s(?:RN|PP|VM)).)*?(\w+\s+VM\w+)', s)
but I get this with the above regex:
print together__
output:
[('no RN', 'le PP3CSD00', 'ver VMII3S0'), ('no RN', 'le PP004DF', 'fallar VM0FD00')]
Which is wrong since the ids are not consecutevely in the string s (RN, PP, VM). How can I fix this regex?. Thanks in advance guys.
You better
You can do this simply with:
list = re.findall(r'\n?\s*\S+\s+(\w+\W+RN\w*)[^\n]*[^\n]*?\n\s*\S+\s+(\w+\W+PP\w*)[^\n]*[^\n]*?\n\s*\S+\s+(\w+\W+VM\w*)[^\n]*', s)
Resulting in:
[('no RN', 'le PP004DF', 'fallar VM0FD00')]
because ver VM is first.
In case you don't get a decent answer soon enough, I think that I may be close to what you want with this:
re.findall(r'\n[^\n]*?\s(.*?\sRN[^\n]*)\n[^\n]*?\s(.*?\sPP[^\n]*)\n[^\n]*?\s(.*?\sVM[^\n]*)\n', s)
I don't know why I get both words in the first item... might be because of the "#" and I did not bother cutting after RN, PP and VM. I guess that if the first step works decently enough, the rest can be easily fixed in post-processing.